算法修炼Day07|454.四数相加II ● 383. 赎金信 ● 15. 三数之和 ● 18. 四数之和

88 阅读4分钟
题目:454. 四数相加 II - 力扣(LeetCode)
想法/思路:

方法一:四层for循环不出意外的超时。 方法二:拆分数据量,四个数组两两组合,将其中一组和加入 map 中,另外一组进行到 map 中取值即可,取到则进行++操作。

代码实现:
class Solution {
    public int fourSumCount(int[] nums1, int[] nums2, int[] nums3, int[] nums4) {
        // 四层for循环
        int count = 0;
        for (int i = 0; i < nums1.length; i++) {
            for (int j = 0; j < nums2.length; j++) {
                for (int k = 0; k < nums3.length; k++) {
                    for (int l = 0; l < nums4.length; l++) {
                        int sum = nums1[i] + nums2[j] + nums3[k] + nums4[l];
                        if (sum == 0) {
                            count++;
                        }
                    }
                }
            }
        }
        return count;
    }
}

class Solution {
    public int fourSumCount(int[] nums1, int[] nums2, int[] nums3, int[] nums4) {
        // 拆分数据量,四个数组两两组合
        Map<Integer, Integer> map = new HashMap<>();
        for (int i = 0; i < nums1.length; i++) {
            for (int j = 0; j < nums2.length; j++) {
                int mid1 = nums1[i] + nums2[j];
                map.put(mid1, map.getOrDefault(mid1, 0) + 1);
            }
        }
        int count = 0;
        for (int i = 0; i < nums3.length; i++) {
            for (int j = 0; j < nums4.length; j++) {
                int mid2 = nums3[i] + nums4[j];
                if (map.get(-mid2) != null) {
                    count += map.get(-mid2);
                }
            }
        }
        return count;
    }
}
题目:383. 赎金信 - 力扣(LeetCode)
想法/思路:

magazine 中获取字符能否组成 ransomNote,且每个字符只能使用一次。显然可以用 map

代码实现:
class Solution {
    public boolean canConstruct(String ransomNote, String magazine) {
        // magazine中获取字符能否组成ransomNote,且每个字符只能使用一次。
        // 显然可以用map
        if (ransomNote.length() > magazine.length()) return false;
        Map<Character, Integer> map = new HashMap<>();
        for (int i = 0; i < magazine.length(); i++) {
            char c1 = magazine.charAt(i);
            map.put(c1, map.getOrDefault(c1, 0) + 1);
        }
        for (int i = 0; i < ransomNote.length(); i++) {
            char c2 = ransomNote.charAt(i);
            if (!map.containsKey(c2)) {
                return false;
            } else if (map.get(c2) == 1) {
                map.remove(c2);
            } else {
                map.put(c2, map.get(c2) - 1);
            }
        }
        return true;
    }
}
题目:15. 三数之和 - 力扣(LeetCode)
想法/思路:

排序、遍历、双指针、去重(三个数分别去重)。 实现细节还差点意思,突然发现找bug的过程就是提升代码理解程度的过程。

代码实现:
class Solution {
    public List<List<Integer>> threeSum(int[] nums) {
        List<List<Integer>> ans = new ArrayList<>();
        // 简单排个序
        Arrays.sort(nums);
        for (int i = 0; i < nums.length - 2; i++) {
            
            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) {
                    ans.add(Arrays.asList(nums[i], nums[left], nums[right]));
                    left++;
                    right--;
                    while (left < right && nums[left] == nums[left - 1]) {
                        left++;
                    }
                    while (left < right && nums[right] == nums[right + 1]) {
                        right--;
                    }
                } else if (sum > 0) {
                    right--;
                } else if (sum < 0) {
                    left++;
                }
            }
        }
        return ans;
    }
}

题目:18. 四数之和 - 力扣(LeetCode)
想法/思路:

排序、双层遍历、双指针、去重。

注意:
JAVA 中八种数据类型及其数据范围都是多少?
在Java中,有以下八种基本数据类型及其数据范围:

1. byte:1个字节,取值范围为-128到127。计算过程如下:
   - 最小值:-2^(8-1) = -2^7 = -128
   - 最大值:2^(8-1) - 1 = 2^7 - 1 = 127

2. short:2个字节,取值范围为-32768到32767。计算过程如下:
   - 最小值:-2^(16-1) = -2^15 = -32768
   - 最大值:2^(16-1) - 1 = 2^15 - 1 = 32767
共计5位数!

3. int:4个字节,取值范围为-2147483648到2147483647。计算过程如下:
   - 最小值:-2^(32-1) = -2^31 = -2147483648
   - 最大值:2^(32-1) - 1 = 2^31 - 1 = 2147483647
共计10位数!

4. long:8个字节,取值范围为-9223372036854775808到9223372036854775807。计算过程如下:
   - 最小值:-2^(64-1) = -2^63 = -9223372036854775808
   - 最大值:2^(64-1) - 1 = 2^63 - 1 = 9223372036854775807
共计19位

5. float:4个字节,取值范围为-3.402823e+38到3.402823e+38。计算过程如下:
   - 最小值:-1.4e^-45 * 2^127 ≈ -3.402823e+38
   - 最大值:(1 - 2^-23) * 2^127 ≈ 3.402823e+38

6. double:8个字节,取值范围为-1.7976931348623157e+308到1.7976931348623157e+308。计算过程如下:
   - 最小值:-1.7e^-308 * 2^1023 ≈ -1.7976931348623157e+308
   - 最大值:(1 - 2^-52) * 2^1023 ≈ 1.7976931348623157e+308

7. boolean:1个字节,取值范围为true或false。

8. char:2个字节,取值范围为0到65535。计算过程如下:
   - 最小值:0
   - 最大值:2^16 - 1 = 65535
代码实现:
class Solution {
    public List<List<Integer>> fourSum(int[] nums, int target) {
        List<List<Integer>> ans = new ArrayList<>();
        Arrays.sort(nums);
        for (int i = 0; i < nums.length; i++) {
            for (int j = nums.length - 1; j > i; j--) {
                
                if (i > 0 && nums[i] == nums[i - 1]) {
                    continue;
                }
                if (j < nums.length - 1 && nums[j] == nums[j + 1]) {
                    continue;
                }
                int left = i + 1, right = j - 1;
                while (left < right) {
                    long sum = (long)nums[i] + nums[j] + nums[left] + nums[right]; // 数据范围需要注意一下
                    if (sum == target) {
                        ans.add(Arrays.asList(nums[i], nums[j], nums[left], nums[right]));
                        left++;
                        right--;
                        while (left < right && nums[left] == nums[left - 1]) {
                            left++;
                        }
                        while (left < right && nums[right] == nums[right + 1]) {
                            right--;
                        }
                    } else if (sum > target) {
                        right--;
                    } else {
                        left++;
                    }
                }
            }
        }
        return ans;
    }
}