我遇到一个问题,我们有一个正数组,我们必须通过对数组元素进行零次或多次更改来严格增加它。
我们被问到使阵列严格增加所需的最小更改次数。
示例
如果数组是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
约束:
数组中的元素数< = 10 ^ 6
每个元素< = 10 ^ 9
注意:
这不是作业,在我的采访中被问到,我无法给出算法。
有人可以给我一个算法吗?
链接到示例测试用例的详细问题 https://www.hackerearth.com/problem/algorithm/find-path/
由于它是迷你/最大问题,所以它听起来像我的动态编程,但我需要帮助。
答案 0 :(得分:7)
这非常接近O(nlogn)中可解决的标准longest increasing subsequence problem。
如果您可以将数字更改为小数,那么答案将是相同的。 (最小变化数量=最长增长子序列的字符串长度)
但是,由于您需要不同的积分值,因此您必须稍微修改标准算法。
考虑如果通过执行x [i] = x [i] -i。
更改数组会发生什么现在需要通过进行最小数量的更改来修改此更改的数组,以使每个元素增加或保持不变。
现在,您可以在此数组中搜索最长的非递减子序列,这将告诉您有多少元素可以保持不变。
但是,这可能仍然使用负整数。
将算法修改为仅使用正数的一种简单方法是在数组的开头附加大量数字。
即。将1,2,9,10,3,15改为-5,-4,-3,-2,-1,1,2,9,10,3,15
然后,您可以确定最佳答案永远不会决定让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
所以回答是改变一个数字。
原始序列
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个数字。
答案 1 :(得分:0)
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);
}
}
}
}
答案 2 :(得分:0)
更改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;
}
答案 3 :(得分:0)
灵感来自@Peter de Rivaz,
我发现此问题的关键条件是:num [i] -i> = num [j] -j> = 0(i> j)。
以下Java代码(O(NlgN))是对标准最长递增子序列算法的略微修改,这里我们跳过所有num [i],其中num [i] -i <0。
export default class WallPaper extends Component {
render() {
const {children} = this.props
return (
<ImageBackground
source={backgroundimg}
imageStyle={{ opacity: 0.9 }}
style={styles.container}
>
{this.props.children}
</ImageBackground>
);
}
}
答案 4 :(得分:0)
具有时空复杂度的地雷解决方案 O(n) 和 O(1) 在 python 中
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)
答案 5 :(得分:-1)
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