对数组每个元素增加一个量,使得数组递增
2014-12-02 21:29
393 查看
一个题目,据说来自Hired online test:
大意:给定一数组arr[],找出一个最小的X,使得在数组每一元素arr[i]上加一个[-X,X]内的值后,数组arr[]严格递增。
思路:
(1)不难看出,如果区间[-X,X]可行,则区间[-X-1,X+1]一定可行,因此我们可以采用二分法探索X的最值
(2)如果数组原本就严格递增,则X = 0
(3)进一步发现,X = max(n, m)时,肯定可行,其中m为数组中的最大值:我们可以通过对每个元素加上一个[-X,X]的值,使得数组离变为0, 1, 2, ..., n-1
(4)如何判断[-X,X]是否是一个有效的区间呢,这样考虑:我们希望变换后的数组严格递增,很容易想到首先让arr[0]变得最小(其他值可以的话,最小值肯定可以),因此arr[0]变为trans[0] = arr[0]-X,对于arr[i],我们把它变成大于trans[i-1]的最小trans[i](其他值可以的话,最小值肯定可以),则arr[i] + inc[i] > arr[i-1] + inc[i-1],即inc[i] =arr[i-1] + inc[i-1] - arr[i] + 1,如果inc[i]
< -X,那我们不得不把inc[i]调大,让inc[i] = -X,如果inc[i] > X,则arr[i]无论如何都不能成为递增数组的一部分,毕竟arr[0, i)已经是最小的可行值了。
每检查一个区间[-X,X]是否可行,我们需要遍历一次数组,而我们需要检查O(log(max(m, n)))个区间,因此时间复杂度为O(nlog(max(m,n))),空间复杂度为O(1)。
根据上述思路,可以得到如下代码:
#!/usr/bin/env python3 # coding: utf-8 """ Challenge 3: Hill Given an array of integer elements Your task is to - write a function that finds the minimum value X that makes possible the following: generate a new array that is sorted in strictly ascending order by increasing or decreasing each of the elements of the initial array with integer values in the [0, X] range. - Example: Having the initial array [5, 4, 3, 2, 8] the minimum value for X is 3. Decrease the first element (5) by 3, decrease the second one (4) by 1, increase the third one (3) by 1, increase the forth one (2) by 3 and do nothing to the last one (8). In the end we obtain the array [2, 3, 4, 5, 8] which is sorted in strictly ascending order. - print the result X to the standard output (stdout) Note that your function will receive the following arguments: - v, which is the array of integers Data constraints - numbers are in ascending order when arranged from the smallest to the largest number - strictly ascending order means that each element is greater than the preceding one (e.g., [1, 2, 2, 3] is NOT strictly ascending order) - the length of the array will not exceed 5000 - the elements of any of the arrays are integer numbers in the [1, 2^31 - 1] range Efficiency constraints - your function is expected to print the result in less than 2 seconds Example Input Output ---------------- ------ v: 5, 4, 3, 2, 8 3 """ def hill(v): # Write your code here # To print results to the standard output you can use print # Example print "Hello world!"
大意:给定一数组arr[],找出一个最小的X,使得在数组每一元素arr[i]上加一个[-X,X]内的值后,数组arr[]严格递增。
思路:
(1)不难看出,如果区间[-X,X]可行,则区间[-X-1,X+1]一定可行,因此我们可以采用二分法探索X的最值
(2)如果数组原本就严格递增,则X = 0
(3)进一步发现,X = max(n, m)时,肯定可行,其中m为数组中的最大值:我们可以通过对每个元素加上一个[-X,X]的值,使得数组离变为0, 1, 2, ..., n-1
(4)如何判断[-X,X]是否是一个有效的区间呢,这样考虑:我们希望变换后的数组严格递增,很容易想到首先让arr[0]变得最小(其他值可以的话,最小值肯定可以),因此arr[0]变为trans[0] = arr[0]-X,对于arr[i],我们把它变成大于trans[i-1]的最小trans[i](其他值可以的话,最小值肯定可以),则arr[i] + inc[i] > arr[i-1] + inc[i-1],即inc[i] =arr[i-1] + inc[i-1] - arr[i] + 1,如果inc[i]
< -X,那我们不得不把inc[i]调大,让inc[i] = -X,如果inc[i] > X,则arr[i]无论如何都不能成为递增数组的一部分,毕竟arr[0, i)已经是最小的可行值了。
每检查一个区间[-X,X]是否可行,我们需要遍历一次数组,而我们需要检查O(log(max(m, n)))个区间,因此时间复杂度为O(nlog(max(m,n))),空间复杂度为O(1)。
根据上述思路,可以得到如下代码:
#include <cstdio> #include <algorithm> using namespace std; //check if we can make arr[] become ascending //by adding a number within [-m, m] to each element bool canMakeAHill(int arr[], int n, int m) { int d = -m, i = 1; for(; i < n; ++i){ d = arr[i-1] + d - arr[i] + 1; if(d > m) return false; if(d < -m) d = -m; } return true; } //find out the minimum number m that we can make arr[] become ascending //by adding a number within [-m, m] to each element int hill(int arr[], int n) { int i, l, r; bool sorted = true; //check if arr[] is sorted already and find out the max element r = arr[0]; for(i = 1; i < n; ++i){ if(arr[i-1] >= arr[i]) sorted = false; else r = max(r, arr[i]); } if(sorted) return 0; //binary search l = 0; r = max(r, n); while(l + 1 < r){ int m = (l + r) >> 1; if(canMakeAHill(arr, n, m)) r = m; else l = m; } return r; } int main() { int arr[] = {5, 4, 3, 2, 8}; printf("%d\n", hill(arr, sizeof(arr)/sizeof(arr[0]))); return 0; }
相关文章推荐
- 给定一个数组,求数组中所有元素的可能组合(每个元素只出现一次),使其和等于给定数的解决办法
- php如何增加一个元素到数组
- 程序员面试题目总结--数组(一)【递归求数组所有元素和、用一个for循环打印出一个二维数组、用递归判断数组是否是递增、有序数组中删除重复元素】
- 给定一个整数sum, 从有N个有序元素的数组中寻找元素a,b,使得a+b的结果最接近sum
- 定义一个int型的一维数组,包含40个元素,用来存储每个学员的成绩,循环产生40个 0~100之间的随机整数,将它们存储到一维数组中,
- Combination Sum II 无序数组中找组合(每个元素只能用一次)使得和为target@LeetCode@LeetCode
- 2014年去哪儿网笔试题--给定一个整型数组,对这个整型数组排序,使得按序拼接数组各元素得到的值最小。
- 增加原型方法写出删除一个数组相同元素的函数
- 数组a中每个元素包含两个值第一个是整型第二个是字符串写一个sort函数以第一个值为键按从小到大排序
- 利用二分查找在循环递增数组中检索一个元素
- 输入一个递增排序的数组的一个旋转,输出旋转数组的最小元素
- 10.1-2 说明如何用一个数组A[1..n]来实现两个栈,使得两个栈中的元素总数不到n时,两者都不会发生上溢,注意PUSH和POP操作的时间应为O(1)。
- 2014年去哪儿网笔试题--给定一个整型数组,对这个整型素组排序,使得按序拼接数组各元素得到的值最小。
- 1.编写一个程序,这个程序把一个整数数组中的每个元素用逗号连接成一个字符串,例如,根据内容为[1][2][3]的数组形成内容
- 利用二分查找在循环递增数组中检索一个元素
- 从三个排好序的整数数组中分别选一个元素,使得这三个元素的最大差最小
- 求k个数组包含每个数组至少一个元素的最小范围(待字闺中,备忘)
- 给定一个数组,求数组中所有元素的可能组合(每个元素只出现一次),使其和等于给定数的解决办法
- 【C语言】求旋转数组的最小数字,输入一个递增排序的数组的一个旋转,输出其最小元素
- 【1】 设一个长度为10的整型数组,  0)要求每个元素的值通过scanf输入,输入完成后,  1)请顺序输出这些整数,  2)请倒序输出这些整数,  3)输出这些数中的最大值,最小值