代码随想录算法训练营第7天| leetcode ● 454.四数相加II ● 383. 赎金信 ● 15. 三数之和 ● 18. 四数之和

● 454.四数相加II

题目链接: https://leetcode.cn/problems/4sum-ii/

解题思路:

第一轮遍历, 记录数组 nums1 和数组 nums2对应元素 之和 , 以及这样的和出现的次数, 记录在hashmap 中.

第二轮遍历,累加 nums3 和数组 nums4 对应元素 之和num,判断 数字0 与 和 num之前的差值,是否在hashmap 中 存在. 如果存在,记录次数,累加这些次数,进行返回.

参考答案:

class Solution {

public int fourSumCount(int[] nums1, int[] nums2, int[] nums3, int[] nums4) {

HashMap<Integer, Integer> hashMap = new HashMap<>();

int index = 0;

for (int mum1 : nums1) {

for (int mum2 : nums2) {

if (hashMap.containsKey(mum1 + mum2)) {

hashMap.put(mum1 + mum2, hashMap.get(mum1 + mum2) + 1);

} else {

hashMap.put(mum1 + mum2, hashMap.getOrDefault(mum1 + mum2, 1));

}

}

}

int num = 0;

for (int mum3 : nums3) {

for (int mum4 : nums4) {

if (hashMap.containsKey(0 - (mum3 + mum4))) {

num += hashMap.get(0 - (mum3 + mum4)) ;

}

}

}

return num;

}

}

● 383. 赎金信

题目链接: https://leetcode.cn/problems/ransom-note/

解题思路:

int num1 = 'a'; num1的值为97, 阿斯克码表的值.

int num2 = 'b' - 'a'; num2的值为1

int num2 = 'c' - 'a'; num2的值为2

创建一个长度为26 (小写字母的个数) 的数组.

小写字母,相比字母的顺序(a,b,c,d,e.......), 对应在阿斯克码表中的值是连续递增的.

单独的字符相减得到的数字,把他们映射到数组的索引位置上,根据映射到的次数,做增加操作.这样就有了字符串magazine的各个字母出现的位置 和 出现次数的对应关系了.

比如 'b'出现第一次在数字中 arr['b'-'a']++ ,也就是arr[1]=1.

再去遍历字符串ransomNote,映射到对应的次数,做减少次数的操作,抵消magazine之前的操作.

最后遍历数组,如果存在元素的值不为空,说明 字符串s 和t中存在字母出现的次数不一样,返回false; 否则true.

参考答案:

class Solution {

public boolean canConstruct(String ransomNote, String magazine) {

char[] chars = ransomNote.toCharArray();

int[] arr = new int[26];

for (char char1 : chars) {

arr[char1-'a']++;

}

char[] chars2 = magazine.toCharArray();

for (char char2 : chars2) {

arr[char2-'a']--;

}

for (int num : arr) {

if(num>0){

return false;

}

}

return true;

}

}

● 15. 三数之和

题目链接: https://leetcode.cn/problems/3sum

给你一个整数数组 nums ,判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i != j、i != k 且 j != k ,同时还满足 nums[i] + nums[j] + nums[k] == 0 。请

你返回所有和为 0 且不重复的三元组。

注意:答案中不可以包含重复的三元组。

解题思路:

用双指针法来实现, 遍历数组, 声明三个变量 int i ; int left=i+1 ; int right = nums.length - 1

三个索引 i ; left ; right 处的值相加的和和 目标数字 0 相比,

i不变的时候,在,满足 left< right的情况,while 循环.

如果>0 ,右边指针right--;

如果<0 ,左边指针left++ ;

如果== 0,把对应数组的值记录在集合里面.

接下来分析,去重的问题.

题目要求: 数组不能重复; i ; left ; right 三个值也不能重复

i 的去重:

本题目是,先固定i,先移动 left 和right两个指针,来寻找满足和为0的三个值.

为什么是: nums[i] == nums[i -1] 而不是nums[i] == nums[i +1]

一组特殊的测试用例: [ -1,0,1 ] 排序后: [ -1,-1,0 ]

如果用后者的逻辑,这桑热书实际是满足要求的,数据不重复,但是数组内的元素可以是不同索引处的重复,用后面这个逻辑,就会把这组数据错过.

if (i>0 && nums[i] == nums[i -1]) {

continue;

}

left 和 right的去重:

(1). 三个值累加和 大于 或者 小于 0的时候,不满足等于条件,即使 nums[right] == nums[right - 1] 或者nums[left] == nums[left +1], 从 left 遍历到 left +1 或者从right 遍历到 right - 1 ,同样不满足等于0的条件,此时会 right-- 或者 left++ ,不用额外去重.

(2) . 三个值累加和 等于 0的时候,满足等于条件.

此时,如果 遇到 nums[right] == nums[right - 1] 或者nums[left] == nums[left +1]的情况,就要right-- 或者 left++. 此操作,在把满足条件的三个值存到集合中的代码 逻辑 之后.

参考答案:

class Solution {

public List<List<Integer>> threeSum(int[] nums) {

List<List<Integer>> list = new ArrayList<>();

Arrays.sort(nums);

int sum = 0;

for (int i = 0; i < nums.length; i++) {

int left = i + 1;

int right = nums.length - 1;

if (i>0 && nums[i] == nums[i -1]) {

continue;

}

while (left < right) {

sum = nums[i] + nums[left] + nums[right];

if (sum > 0) {

right--;

} else if (sum < 0) {

left++;

} else {

list.add(Arrays.asList(nums[i], nums[left], nums[right]));

while (right > left && nums[right] == nums[right - 1]) {

right--;

}

while (right > left && nums[left] == nums[left +1]) {

left++;

}

right--;

left++;

}

}

}

return list;

}

}

● 18. 四数之和

题目链接: https://leetcode.cn/problems/4sum/

解题思路:

这个题目时在三数之和的基础上 变化了一下,思路还是相似的.

原来是一次for 循环, 遍历时的索引 i , 和 left ,right 三个变量对应处的数组的值,累加求和.

原来是对 i,和 left ,right 分别去重.

现在需要多一次 for循环,遍历时的索引 i , j, 和 left ,right 四个变量对应处的数组的值,累加求和.

现在是对 i, j 和 left ,right 分别去重.

参考答案:

class Solution {

public List<List<Integer>> fourSum(int[] nums, int target) {

Arrays.sort(nums);

List<List<Integer>> lists = new ArrayList<>();

long num = 0;

for (int i = 0; i < nums.length; i++) {

for (int j = i + 1; j < nums.length; j++) {

if(i>0 && nums[i]==nums[i-1]){

continue;

}

if(j >i + 1 && nums[j]==nums[j-1]){

continue;

}

int left = j + 1;

int right = nums.length - 1;

while (left < right) {

num = (long)nums[left] + nums[right] + nums[i] + nums[j];

if (left < right && num > target) {

right--;

} else if (left < right && num < target) {

left++;

} else {

lists.add(Arrays.asList(nums[left], nums[right], nums[i], nums[j]));

while (left<right && nums[left]==nums[left+1]){

left++;

}

while (left<right && nums[right]==nums[right-1]){

right--;

}

right--;

left++;

}

}

}

}

return lists;

}

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值