您的位置:首页 > 其它

LintCode每日一练-限制条件子集

2018-03-08 21:18 260 查看

问题:限制条件子集

给一个数组,给定一个target,求满足以下条件的子集个数:

条件:子集中的最小值+最大值小于给定target。

问题链接:http://www.lintcode.com/zh-cn/problem/subset-with-target/

样例

给出 array = [1,5,2,4,3], target = 4, 返回 2。

解释:只有子集[1],[1,2]满足条件。所以答案是2

解法一

最容易想到的方案是:以[1,5,2,4,3]为例,先对数组进行排序,

变成[1,2,3,4,5],然后从小到大枚举其可能的区间,[1,2],[1,2,3],[1,2,3,4],[1,2,3,4,5],[2,3],[2,3,4],[2,3,4,5]等等…,一旦发现区间的首尾和小于target,则子集总数加上2的(区间长度 - 2)次幂,然后再遍历每个单个元素,每次有元素的两倍小于target,则子集总数再加上1。代码如下:

public long power(int exp){
long result = 1;
for ( int i = 0; i < exp; i++){
result *= 2;
}
return result;
}

/**
* @param nums: the array
* @param target: the target
* @return: the number of subsets which meet the following conditions
*/
public long subsetWithTarget(int[] nums, int target) {
// Write you code here
Arrays.sort(nums);
long sum = 0;
for ( int i = 0; i < nums.length; i++ ){
if ( 2 * nums[i] < target  ){
sum++;
}
for ( int j = i + 1; j < nums.length; j++ ){
if ( nums[i] + nums[j] < target ){
sum += power(j-i-1);
}
}
}
return sum;
}


这里也可以不用写那个power函数,而是直接用左移运算(“<<”)替代。

提交,排名如下:



改进解法一

解法一其实做了一些多余的运算,比如当我发现[1,2,3,4]满足target时,那么[1,2],[1,2,3]也是肯定满足的,而且他们的和可以用等比数列求和公式直接算出,所以这个时候不需要一个个判定,直接找到从某个数开始的最长区间,然后计算一下等比数列求和公式就可以了,代码如下:

/**
* @param nums: the array
* @param target: the target
* @return: the number of subsets which meet the following conditions
*/
public long subsetWithTarget(int[] nums, int target) {
Arrays.sort(nums);

long sum = 0;
for ( int i = 0; i < nums.length; i++ ){
if ( 2 * nums[i] < target ){
sum++;
}
int rest = target - nums[i];
for ( int j = nums.length - 1; j > i; j-- ){
if ( nums[j] < rest ){
sum += (1 - (1L << (j - i))) / (1 - 2);
break;
}
}
}
return sum;
}


提交,排名上升到第六名:

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: