454.四数相加II
两数相加的变种
- 不要忘记
map.getOrDefault()
方法
class Solution {
public int fourSumCount(int[] nums1, int[] nums2, int[] nums3, int[] nums4) {
int res = 0, sum, target;
Map<Integer, Integer> record = new HashMap<>();
for(int n1: nums1){
for(int n2: nums2){
sum = n1+n2;
// map.put(sum, map.getOrDefault(sum, 0) + 1); 使用这个更好
if(!record.containsKey(sum)) record.put(sum, 1);
else{
record.put(sum, record.get(sum)+1);
}
}
}
for(int n3: nums3){
for(int n4:nums4){
// 同上
target = 0 - n3 - n4;
if(record.containsKey(target)) res += record.get(target);
}
}
return res;
}
}
383. 赎金信
易错点:
- 边缘条件:不是长度不相等
- 同上,由于长度不相等,所以对两数组的遍历也不同。
- 使用
str.toCharArray()
方法,比str.charAt()
更好。
class Solution {
public boolean canConstruct(String ransomNote, String magazine) {
int len1 = ransomNote.length(), len2 = magazine.length();
if(len1>len2) return false;
int[] record = new int[26];
int i;
for(i=0; i<len2; i++){
if(i<len1) record[ransomNote.charAt(i)-'a']--;
record[magazine.charAt(i)-'a']++;
}
for(i=0; i<26; i++){
if(record[i]<0) return false;
}
return true;
}
}
随想录解法:
class Solution {
public boolean canConstruct(String ransomNote, String magazine) {
// shortcut
if (ransomNote.length() > magazine.length()) {
return false;
}
// 定义一个哈希映射数组
int[] record = new int[26];
// 遍历
for(char c : magazine.toCharArray()){
record[c - 'a'] += 1;
}
for(char c : ransomNote.toCharArray()){
record[c - 'a'] -= 1;
}
// 如果数组中存在负数,说明ransomNote字符串中存在magazine中没有的字符
for(int i : record){
if(i < 0){
return false;
}
}
return true;
}
}
15. 三数之和 (难)
这道题对我来说比较难,看了代码随想录才有思路。
- 双指针法:前提——数组排序(因为该题不需要返回下标)
- i 的去重:与前一个
√
- - - 与后一个×
,因为需要添加到集合中。 - left 与 right 的去重:应该放入一个
while
循环进行去重。而且,比较的是left与left+1,right与right-1,这时没必要检查是否越界,同时也更好写一点。 - 循环条件:添加完结果之后,需要更新循环条件。
class Solution {
public List<List<Integer>> threeSum(int[] nums) {
List<List<Integer>> res = new ArrayList<>();
Arrays.sort(nums);
int n = nums.length;
for(int i=0; i<n-2; i++){
// 边缘条件
if(nums[i]>0) return res;
// i的去重
if(i>0 && nums[i]==nums[i-1]) continue;
int left = i+1, right = n-1;
while(left<right){
int sum = nums[i] + nums[left] + nums[right];
if(sum==0){
// 这里的去重逻辑有些笨拙
if (left>i+1 && nums[left]==nums[left-1]){
left++;
continue;
}
if (right<n-1 && nums[right]==nums[right+1]){ // left, right的去重
right--;
continue;
}
res.add(Arrays.asList(nums[i], nums[left], nums[right]));
// 不要忘记,添加res之后,需要更新循环条件
left++;
right--;
} else if(sum>0){
right--;
} else if(sum<0){
left++;
}
}
}
return res;
}
}
代码随想录的循环:比我的更好。
class Solution {
public List<List<Integer>> threeSum(int[] nums) {
List<List<Integer>> result = new ArrayList<>();
Arrays.sort(nums);
// 找出a + b + c = 0
// a = nums[i], b = nums[left], c = nums[right]
for (int i = 0; i < nums.length; i++) {
// 排序之后如果第一个元素已经大于零,那么无论如何组合都不可能凑成三元组,直接返回结果就可以了
if (nums[i] > 0) {
return result;
}
if (i > 0 && nums[i] == nums[i - 1]) { // 去重a
continue;
}
int left = i + 1;
int right = nums.length - 1;
while (right > left) {
int sum = nums[i] + nums[left] + nums[right];
if (sum > 0) {
right--;
} else if (sum < 0) {
left++;
} else {
result.add(Arrays.asList(nums[i], nums[left], nums[right]));
// 去重逻辑应该放在找到一个三元组之后,对b 和 c去重
while (right > left && nums[right] == nums[right - 1]) right--;
while (right > left && nums[left] == nums[left + 1]) left++;
right--;
left++;
}
}
}
return result;
}
}
18. 四数之和(需要注意小细节)
简单点:在三数之和的基础上,再套一层循环。
复杂点:很多处细节需要注意,与三数不同。
- 边缘条件(剪枝):
if (nums[i] > 0)
->if(nums[i]>=0 && nums[i]>target)
,if(nums[k] + nums[i]>=0 && nums[i]+nums[k]>target )
并且,应该使用break,而非直接return。(只是剪枝)
同时,目标不再是0,而是一个具体值target。
class Solution {
public List<List<Integer>> fourSum(int[] nums, int target) { // 注意:是target,而不是0
List<List<Integer>> res = new ArrayList<>();
Arrays.sort(nums);
int n = nums.length;
for(int i=0; i<n-3; i++){
// 边缘条件:注意,不能那么简单
if(nums[i]>=0 && nums[i]>target) return res; // 建议用break
// i的去重
if(i>0 && nums[i]==nums[i-1]) continue;
for(int k=i+1; k<n-2; k++){
// 边缘条件
if(nums[k] + nums[i]>=0 && nums[i]+nums[k]>target ) break; // 不break而是return会有遗漏
// k的去重
if(k>i+1 && nums[k]==nums[k-1]) continue;
int left = k+1, right = n-1;
while(left<right){
int sum = nums[i] + nums[k] + nums[left] + nums[right];
if(sum>target){
right--;
}else if(sum<target){
left++;
}else{
res.add(Arrays.asList(nums[i], nums[k], nums[left], nums[right]));
while(left<right && nums[left]==nums[left+1]) left++;
while(left<right && nums[right]==nums[right-1]) right--;
right--;
left++;
}
}
}
}
return res;
}
}