日练三题,冰冻三尺非一日之寒。
今日题目:
1、组合加法IV; | tag:DP
2、最接近的三数字和; |tag:数组、两指针
3、查找目标范围。 |tag:数组|二分查找
今日摘录:
一个人爱什么,就死在什么上。
——老舍
377. Combination Sum IV | Difficulty: Medium
Given an integer array with all positive numbers and no duplicates, find the number of possible combinations that add up to a positive integer target.
Example:
nums = [1, 2, 3]
target = 4
The possible combination ways are:
(1, 1, 1, 1)
(1, 1, 2)
(1, 2, 1)
(1, 3)
(2, 1, 1)
(2, 2)
(3, 1)
Note that different sequences are counted as different combinations.
Therefore the output is 7.
Follow up:
What if negative numbers are allowed in the given array?
How does it change the problem?
What limitation we need to add to the question to allow negative numbers?
tag:DP
题意:找到数组元素中部分和等于目标值的组合数
思路:
1、思路很好理清,以nums = [1,2,3] target = 4为例。如果我们需要找到和为1的组合可能数,怎么去做?用res[i]表示和为i的可能性,res[0] = 1,需要找和为1的可能性,只可能是nums中有1 这一种情况,这个时候res[1] = 1,然后再去求res[2],2无非就是两种情况,第一种情况res[1]+1,也就是在res[1]的基础上再碰到一个1,因为res[1]只有一种情况,随意再碰到一个1还是只有一种情况,第二种情况是res[0]+2,也就是res[0]的情况可能性加上碰到一个2,也是一种情况,合起来res[2]就是2种可能性,继续往下去计算,res[3] = (res[2]+1存在)+(res[1]+2存在)+(res[0]+3存在)=4,res[4]=7.
class Solution {
public:
int combinationSum4(vector<int>& nums, int target) {
vector<int>res(target+1,0);
res[0] = 1;
for(int i=1;i<=target;i++)
{
for(int num:nums)
{
if(i>=num) res[i]+=res[i-num];
}
}
return res[target];
}
};
结果:4ms
16. 3Sum Closest | Difficulty: Medium
Given an array S of n integers, find three integers in S such that the sum is closest to a given number, target. Return the sum of the three integers. You may assume that each input would have exactly one solution.
For example, given array S = {-1 2 1 -4}, and target = 1.
The sum that is closest to the target is 2. (-1 + 2 + 1 = 2).
tag: 数组|两指针
题意:给定一个n个整数的数组,找到S中的三个整数使得和最接近给定数值。
思路:
1、首先对数组进行排序,然后运用三个指针,第一个指针确定第一个元素,第二个指针和第三个指针在剩余元素的两头,如果大了就移动后面的指针,小了就移动前面的指针,这样不断更新最小的误差,就能得到最终结果,复杂度O(N^2)
class Solution {
public:
int threeSumClosest(vector<int>& nums, int target) {
vector<int> v(nums.begin(),nums.end());
int n = nums.size();
sort(v.begin(),v.end());
if(nums.size()<=3) return accumulate(v.begin(), v.end(), 0);
int res = v[0]+v[1]+v[2];
for(int i=0;i<n-2;i++)
{
int j = i+1;
int k = n-1;
while(j<k)
{
int sum = v[i]+v[j]+v[k];
if(abs(sum-target)<abs(res-target))
{
res = sum;
}
if(abs(sum-target)==0) return sum;
(sum>target)? k--:j++;
}
}
return res;
}
};
结果:16ms
34. Search for a Range | Difficulty: Medium
Given a sorted array of integers, find the starting and ending position of a given target value.
Your algorithm’s runtime complexity must be in the order of O(log n).
If the target is not found in the array, return [-1, -1].
For example,
Given [5, 7, 7, 8, 8, 10] and target value 8,
return [3, 4].
tag:数组|二分查找
题意:给定一个整型数组,找到目标值的起始和终止位置。
思路:
1、二分查找的思想,首先找左边界的时候,应该是mid位置值小了就将left=mid+1,mid值大了就right=mid-1,否则就是相等,这个时候左边界可能在mid的左边,也可能就是mid,不过无论如何将right设置成mid就可以保证不出错。照此找出左边界之后,以左边界为左分界线,最右为又分界线开始二分查找,这时候mid只有两种情况,等于target和大于target,等于的时候就将left = mid,大于就将right = mid-1.这里为了防止最后剩下2个元素并且相等的时候形成死循环,可以设置元素在二分的时候向右边倾斜一点,即原本偶数个数取偏左,现在改成偏右。
class Solution {
public:
vector<int> searchRange(vector<int>& nums, int target) {
vector<int>res(2,-1);
int left = 0,right = nums.size()-1;
while(left<right)
{
int mid = left+(right-left)/2;
if(nums[mid]<target) left = mid+1;
else if(nums[mid]>target) right = mid-1;
else right = mid;
}
if(nums[left]!=target) return res;
else res[0] = left;
right = nums.size()-1;
while(left<right)
{
int mid = left+(right-left)/2+1;
if(nums[mid]>target) right = mid-1;
else left = mid;
}
res[1] = right;
return res;
}
};
结果:12ms
第二次刷代码
class Solution {
public:
vector<int> searchRange(vector<int>& nums, int target) {
vector<int> res(2,-1);
int n =nums.size();
if(n==0 || target<nums[0] || target>nums[n-1]) return res;
int l = 0,r = n-1;
while(l<r)
{
int mid = l+(r-l)/2;
if(nums[mid]<target) l = mid+1;
else r = mid;
}
if(nums[l]==target) res[0] = l;
else return res;
l=0,r=n-1;
while(l<r)
{
int mid = l+(r-l+1)/2;
if(nums[mid]>target) r=mid-1;
else l=mid;
}
if(nums[l]==target) res[1] = l;
return res;
}
};
结果:12ms