没封面不好看感觉........
今天下班太晚了,能做到哪里是哪里,就看下思路大概对着码一下练练手。mark一下,周末补回来。
1.四数相加II:代码随想录 (programmercarl.com)
力扣链接:. - 力扣(LeetCode)
这个题简单点的原因是没有去重的操作,给了四个数组看似很麻烦其实很方便,四数相加很容易变为两数相加,这两个数就是分别从A+B和C+D中集合在一起的。
具体看代码,记录下,详细思路见网站和B站链接。学透哈希表,map使用有技巧!LeetCode:454.四数相加II_哔哩哔哩_bilibili
package LuStudy;
import java.util.HashMap;
import java.util.Map;
/*
* 四数相加II
*
* https://leetcode.cn/problems/4sum-ii/
*/
public class _7_1FourNumbersEachPlus {
private static int getFourPlus(int[] numsA, int[] numsB, int[] numsC, int[] numsD) {
Map<Integer, Integer> map = new HashMap<>();
for (int a : numsA) {
for (int b : numsB) {
map.put(a + b, map.getOrDefault(a + b, 0) + 1);
}
}
int res = 0;
for (int c : numsC) {
for (int d : numsD) {
res += map.getOrDefault(0 - c - d, 0);// 这两边default的含义不一样
}
}
return res;
}
public static void main(String[] args) {
int[] numsA = { 1, 2 };
int[] numsB = { -2, -1 };
int[] numsC = { -1, 2 };
int[] numsD = { 0, 2 };
System.out.println(getFourPlus(numsA, numsB, numsC, numsD));
}
}
2.赎金信:代码随想录 (programmercarl.com)
力扣链接:. - 力扣(LeetCode)
这个跟异位字母词那道题比较像,而且只出现小写字母,所以可以定义一个26大小的数组,查询也比较方便,修改对应位置的值也直接覆盖,不会删除数组元素,所以可以用数组解题。
map也不是不可以,就像卡哥说的,map比较占用内存空间。
因为map要维护红黑树或者哈希表,而且还要做哈希函数,是费时的!数据量大的话就能体现出来差别了。 所以数组更加简单直接有效!
只有最后的判断条件不同,其他操作都一样。
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;
}
}
周末再粘一个map的用法,大概就是先遍历杂志的单词,统计value。再遍历赎金数组,对应的value减一下,最后遍历所有value,有<0的就是false了。否则就true。大概是这个思路。
这两个题没时间写了,再看下思路。
3.三数之和:代码随想录 (programmercarl.com)
力扣链接:. - 力扣(LeetCode)
先是看了提醒,说双指针比较容易。还没细究原因。但是一看题目三数之和确实知道双指针大概怎么写了。不过想和写还是两说,最好自己写下,周末补上。
双指针法:外层有个for循环,再在for内层定义左右双指针。循环遍历,有符合条件的记录下数组[i,left,right]。大概就是这个思路。还有个细节,for只循环到倒数第三个,即i<nums.length-2。因为到倒数第三个了,双指针只有一个选择,判断下满足不满足就行了。
再看了下思路:数组先排序一下。因为不用输出下标,只输出数的组合。排序后外层for照常定义,内层可以定义左指针最左即i+1,外层可以定义最右len-1(下标),这样子看target-i剩下的数
如果nums[i] + nums[left] + nums[right] > 0 就说明 此时三数之和大了,因为数组是排序后了,所以right下标就应该向左移动,这样才能让三数之和小一些。
如果 nums[i] + nums[left] + nums[right] < 0 说明 此时 三数之和小了,left 就向右移动,才能让三数之和大一些,直到left与right相遇为止。
代码(双指针法)粘一下:
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;
}
}
4.四叔之和:代码随想录 (programmercarl.com)
力扣链接:. - 力扣(LeetCode)