【问题标题】:Minimum no of changes required to make array strictly increasing使数组严格增加所需的最小更改次数
【发布时间】:2014-01-10 15:50:49
【问题描述】:

我有一个问题,我们有一个正数数组,我们必须通过对数组元素进行零次或多次更改来使其严格递增。

我们被问到使数组严格增加所需的最少更改次数。

示例

如果数组是 1 2 9 10 3 15

如果将 3 更改为 12 到 14 之间的某个数字,则 ans=1。

如果 1 2 2 2 3 4 5

ans=5

因为将 2 更改为 3,然后 2 更改为 4,然后 3 更改为 5,然后 4 更改为 6,然后 5 更改为 7

约束:

数组元素个数

每个元素

注意:

这不是作业,在我的面试中被问到,我无法给出算法。

谁能给我一个算法?

链接到示例测试用例的详细问题 https://www.hackerearth.com/problem/algorithm/find-path/

因为它是最小/最大问题,所以对我来说这听起来像是动态编程,但我需要帮助。

【问题讨论】:

  • 作业与否,您仍然应该尝试解决问题。给定的限制使它听起来很像一场编程竞赛。
  • 我假设对非负数/正数也有一些限制,否则,对于第二个示例,您可以将 1 更改为 -1 并将 (1st) 2 更改为 0 和 (2nd) 2到 1。
  • 不需要动态!
  • 您是否必须实际确定所需的更改,或者只是确定需要进行的更改数量?如果是后一种情况,我认为扫描列表一次并注意当前有多少元素不符合标准,并在更改一个元素时进行一些额外的间隔跟踪以注意可能会破坏可能尚未破坏的相邻元素的方式去...

标签: algorithm dynamic-programming


【解决方案1】:

提示 1

这非常接近标准的longest increasing subsequence problem,可以在 O(nlogn) 中解决。

如果您可以将数字更改为小数,那么答案将是相同的。 (最小变化次数=字符串长度-最长递增子序列长度)

但是,由于您需要不同的整数值,您将不得不稍微修改标准算法。

提示 2

考虑一下如果通过执行 x[i]=x[i]-i 来更改数组会发生什么。

您现在需要通过进行最少数量的更改来修改这个已更改的数组,以使每个元素增加或保持不变。

您现在可以在此数组中搜索最长的非递减子序列,这将告诉您有多少元素可以保持不变。

但是,这仍可能使用负整数。

提示 3

将算法修改为仅使用正数的一种简单方法是在数组的开头附加大量数字。

即将 1,2,9,10,3,15 更改为 -5,-4,-3,-2,-1,1,2,9,10,3,15

那么您可以确定最佳答案永远不会决定使 1 变为负数,因为要使所有负数变小会花费很多。

(您也可以修改最长递增子序列算法以获得额外的约束,但这在面试情况下可能更难正确编码。)

示例 1

在最初的例子中遵循这个:

原序列

1,2,9,10,3,15

在开始时添加虚拟元素

-5,-4,-3,-2,-1,1,2,9,10,3,15

在数组中减去位置

-5,-5,-5,-5,-5,-4,-4,2,2,-6,5

找到最长的非递减序列

-5,-5,-5,-5,-5,-4,-4,2,2,*,5

所以答案是改变一个数字。

示例 2

原序列

1,2,2,2,3,4,5

在开始时添加虚拟元素

-5,-4,-3,-2,-1,1,2,2,2,3,4,5

在数组中减去位置

-5,-5,-5,-5,-5,-4,-4,-5,-6,-6,-6,-6

找到最长的非递减序列

-5,-5,-5,-5,-5,-4,-4,*,*,*,*,*

所以答案是改变5个数字。

【讨论】:

  • 我们可以在不添加虚拟节点的情况下这样做吗?其次,如果最后一个不是 10^9,那么我们必须添加 10^9 个负虚拟节点,这会增加我们的复杂性。而在 c/c++ 中,我们不能占用那么多内存。
  • @PeterdeRivaz 你错了,你的方法不起作用,例如50,51,50,50,52,53,57,因为你的方法总是会改变下一个位置的数字,并且永远不会倒退,因为你在添加一个递增的数组开始..
  • 只需要添加一个10^6个虚拟节点(与序列长度相同,不是最大数量)。您也可以在不添加虚拟节点的情况下执行此操作,但这需要对标准查找最长递增子序列算法进行轻微修改
  • @EugenHalca 我建议的方法可以减少数字,不低于0。查找最长的非减少子序列是选择不变的数字。更改后的数字可以上升或下降。
【解决方案2】:

O(nlogn)运行时间

import java.util.ArrayList;
    import java.util.Scanner;

    public class Modify_The_Sequence {
        private static int n;
        private static int[] a;
        private static ArrayList<Integer> b;
        private static ArrayList<Integer> c;

        public static void main(String args[]) {
            Scanner d = new Scanner(System.in);

            n = d.nextInt();

            b = new ArrayList<>();
            c = new ArrayList<>();
            for (int i = 0; i < n; i++) {
                int x = d.nextInt();
                if (x - (i + 1) >= 0) {
                    b.add(x - (i + 1));
                }

            }

            /*
             * b.clear(); b.add(1); b.add(7); b.add(10); b.add(2); b.add(3);
             */
            // System.out.println(b);
            c.add(b.get(0));
            solve();
            System.out.println(n - c.size());
            // System.out.println(c);
        }

        private static void solve() {
            // TODO Auto-generated method stub
            for (int i = 1; i < b.size(); i++) {
                binaerysearch(0, c.size() - 1, i);
            }
        }

        private static void binaerysearch(int i, int j, int k) {
            // TODO Auto-generated method stub
            int p = (i + j) / 2;
            if (i == j) {

                if (c.get(i) <= b.get(k)) {
                    if (i == c.size() - 1)
                        c.add(b.get(k));
                    else {

                        c.add(i + 1, b.get(k));
                        c.remove(i + 2);
                    }
                } else if (c.get(i) > b.get(k)) {
                    c.add(i, b.get(k));
                    c.remove(i + 1);

                }

            } else {
                if (c.get(p) > b.get(k)) {
                    if (p - 1 > i)
                        binaerysearch(i, p - 1, k);
                    else
                        binaerysearch(i, i, k);
                } else if (c.get(p) <= b.get(k)) {
                    if (p + 1 < j)
                        binaerysearch(p + 1, j, k);
                    else
                        binaerysearch(j, j, k);
                }
            }
        }
    }

【讨论】:

    【解决方案3】:

    更改Longest Increasing Sequence 以适应在两个连续递增的元素之间压缩整数值可以确保我们在适当的位置具有整数值。

    修改后的 LIS 代码:

    int convert(vector<int> v){
    vector<int> lis(v.size(), 1);  
    for(int i = 1; i < v.size(); i++){   
        for(int j = 0; j < i; j++){  
            if(v[i] > v[j] && lis[i] < lis[j]+1 && (i-j) <= (v[i]-v[j]))   
                lis[i] = lis[j]+1;  
        }  
    }  
    int max_lis = 0;  
    for(int i = 0; i < v.size(); i++)  
        max_lis = max(max_lis, lis[i]);  
    int ans = v.size() - max_lis;
    return ans;
    }
    

    【讨论】:

      【解决方案4】:

      灵感来自@Peter de Rivaz 的热门歌曲,

      我发现这个问题的关键条件是:num[i]-i >= num[j]-j >= 0 (i > j)。

      下面的Java代码(O(NlgN))是对标准最长递增子序列算法的轻微修改,这里我们跳过所有num[i],其中num[i]-i

        static int resolve(int... nums) {
          int[] dp = new int[nums.length];
          dp[0] = nums[0];
          int right = 0;
          for (int i = 1; i < nums.length; i++) {
            if (nums[i] >= i) {
              int realNum = nums[i] - i;
              if (realNum >= dp[right]) {
                right++;
                dp[right] = realNum;
              } else {
                dp[binarySearch(dp, 0, right, realNum)] = realNum;
              }
            }
          }
          return nums.length - (right + 1);
        }
      
        static int binarySearch(int[] nums, int left, int right, int key) {
          while (left <= right) {
            int mid = (left + right) >>> 1;
            if (nums[mid] > key) {
              right = mid - 1;
            } else {
              left = mid + 1;
            }
          }
          return left;
        }
      

      【讨论】:

        【解决方案5】:

        具有时间和空间复杂性的矿山解决方案 在 python 中的 O(n) 和 O(1)

        arr = [1,2,2,2,3,4,5]
        count = 0
        for i in range(len(arr)-1):
            if(arr[i]>=arr[i+1]):
                arr[i+1] = arr[i]+1
                count += 1
        print(count)
        

        【讨论】:

          【解决方案6】:

          O(n) 运行时间:

          def min_changes(li):
            change, check = 0, 0
            li_len = len(li)
            if li_len in [0,1]:
              return change
            else:
              check = li[0]
            for i in range(1, len(li)):
              if check >= li[i]:
                li[i] = check +1
                change += 1
                check += 1
              else:
                check = li[i]
            return change
          

          【讨论】:

          • 虽然这段代码 sn-p 可以解决问题,including an explanation 确实有助于提高您的帖子质量。请记住,您正在为将来的读者回答问题,而这些人可能不知道您的代码建议的原因。也请尽量不要用解释性的 cmets 挤满你的代码,这会降低代码和解释的可读性!
          • 在尝试回答更多问题之前,请阅读How do I write a good answer?
          猜你喜欢
          • 2021-05-29
          • 2020-12-30
          • 1970-01-01
          • 2016-09-28
          • 1970-01-01
          • 2015-01-06
          • 2021-03-22
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多