今日内容
454.四数相加II 383. 赎金信 15. 三数之和 18. 四数之和
四数相加II
解题思路
- 使用hashmap键是前两个数组的和,值是出现的数量
- 遍历后两个数组,找到如果 0-(c+d) 在map中出现过的话,就用count把map中key对应的value也就是出现次数统计出来
实现
Java
class Solution {
public int fourSumCount(int[] nums1, int[] nums2, int[] nums3, int[] nums4) {
HashMap<Integer,Integer> hashmap = new HashMap<>();
int res = 0;
for(int i:nums1){
for(int j :nums2){
int temp = i+j;
if(hashmap.containsKey(temp)){
hashmap.put(temp,hashmap.get(temp)+1);
}
else{
hashmap.put(temp,1);
}
}
}
for(int i:nums3){
for(int j:nums4){
int temp = i+j;
if(hashmap.containsKey(0-temp)){
res += hashmap.get(0-temp);
}
}
}
return res;
}
}
C++
class Solution {
public:
int fourSumCount(vector<int>& nums1, vector<int>& nums2, vector<int>& nums3, vector<int>& nums4) {
unordered_map<int,int> map;
for(int a : nums1){
for(int b : nums2){
map[a+b]++;
}
}
int count = 0;
for(int c: nums3){
for(int d: nums4){
if(map.find(0-(c+d)) != map.end()){
count += map[0-(c+d)];
}
}
}
return count;
}
};
赎金信
解题思路
- 使用数组记录magazine中字母出现的次数,遍历ransomNote次数count–,没有小于0的count表示可以
实现
Java
class Solution {
public boolean canConstruct(String ransomNote, String magazine) {
int[] record = new int[26];
for(char c : magazine.toCharArray()){
record[c-'a'] += 1;
}
for(char c : ransomNote.toCharArray()){
record[c-'a'] -= 1;
}
for(int i=0;i<26;i++){
if(record[i]<0) return false;
}
return true;
}
}
C++
class Solution {
public:
bool canConstruct(string ransomNote, string magazine) {
int record[26] = {0};
if(ransomNote.length()>magazine.length()){
return false;
}
for(int i=0;i<magazine.length();i++){
record[magazine[i]-'a']++;
}
for(int i=0;i<ransomNote.length();i++){
record[ransomNote[i]-'a']--;
if(record[ransomNote[i]-'a']<0){
return false;
}
}
return true;
}
};
三数之和
解题思路
- 使用双指针,首先对数据升序排列,数组遍历,left指针指向遍历元素的下一个,right指向末尾
- 当遍历的元素大于0,直接返回res,当sum>0,right–,sum<0,left++,0存储结果
- 对左右指针指向的元素去重,如果和下一个元素相等,向下面移位,还需要最后移位,指向不同的元素
实现
Java
class Solution {
public List<List<Integer>> threeSum(int[] nums) {
List<List<Integer>> res = new ArrayList<>();
Arrays.sort(nums);
for(int i=0;i<nums.length;i++){
if(nums[i]>0) return res;
if(i>0 && nums[i]==nums[i-1]) continue;
int left = i+1,right = nums.length-1;
while(left<right){
int sum = nums[i]+nums[left]+nums[right];
if(sum<0){
left++;
}
else if(sum>0){
right--;
}
else{
res.add(Arrays.asList(nums[i],nums[left],nums[right]));
while(left<right && nums[right]==nums[right-1]) right--;
while(left<right && nums[left]==nums[left+1]) left++;
left++;
right--;
}
}
}
return res;
}
}
C++
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
vector<vector<int>> res;
sort(nums.begin(),nums.end());
for(int i=0;i<nums.size();i++){
if(nums[i]>0) return res;
if(i>0 && nums[i] == nums[i-1]) continue;
int left = i+1;
int right = nums.size()-1;
while(left<right){
if(nums[i]+nums[left]+nums[right]>0){
right--;
}
else if(nums[i]+nums[left]+nums[right]<0){
left++;
}
else{
res.push_back(vector<int>{nums[i],nums[left],nums[right]});
while(left<right && nums[right]==nums[right-1]) right--;
while(left<right && nums[left]==nums[left+1]) left++;
left++;
right--;
}
}
}
return res;
}
};
四数之和
解题思路
- 其实在三数之和上添加一层遍历,在去重和剪枝上有不同,而且不是判断和与0,是目标target,会存在数字溢出可能
- 剪枝比较当前数字和target的大小,去重是和上一位数字相比
实现
Java
class Solution {
public List<List<Integer>> fourSum(int[] nums, int target) {
List<List<Integer>> res = new ArrayList<>();
Arrays.sort(nums);
for(int i=0;i<nums.length;i++){
if(nums[i]>0 && nums[i]>target) return res;
if(i>0 && nums[i]==nums[i-1]) continue;
for(int j=i+1;j<nums.length;j++){
if(j>i+1 && nums[j]==nums[j-1]) continue;
int left = j+1,right = nums.length-1;///
while(left<right){
int sum = nums[i]+nums[j]+nums[left]+nums[right];
if(sum<target){
left++;
}
else if(sum>target){
right--;
}
else{
res.add(Arrays.asList(nums[i],nums[j],nums[left],nums[right]));
while(left<right && nums[right]==nums[right-1]) right--;
while(left<right && nums[left]==nums[left+1]) left++;
left++;
right--;
}
}
}
}
return res;
}
}
C++
class Solution {
public:
vector<vector<int>> fourSum(vector<int>& nums, int target) {
vector<vector<int>> res;
sort(nums.begin(),nums.end());
for(int k=0;k<nums.size();k++){
if (nums[k] > target && nums[k] >= 0) {//剪枝
break;
}
if (k > 0 && nums[k] == nums[k - 1]) {//去重
continue;
}
for(int i=k+1;i<nums.size();i++){
if (nums[k] + nums[i] > target && nums[k] + nums[i] >= 0) {//剪枝
break;
}
if (i > k + 1 && nums[i] == nums[i - 1]) {//去重
continue;
}
int left = i+1;
int right = nums.size()-1;
while(left<right){
if((long)nums[k]+nums[i]+nums[left]+nums[right]>target){//会溢出
right--;
}
else if((long)nums[k]+nums[i]+nums[left]+nums[right]<target){
left++;
}
else{
res.push_back(vector<int>{nums[k],nums[i],nums[left],nums[right]});
while(left<right && nums[right]==nums[right-1]) right--;
while(left<right && nums[left]==nums[left+1]) left++;
left++;
right--;
}
}
}
}
return res;
}
};