两数相加
题目链接:454. 四数相加 II
本题解题步骤:
- 首先定义 一个hashmap,key放a和b两数之和,value 放a和b两数之和出现的次数。
- 遍历大A和大B数组,统计两个数组元素之和,和出现的次数,放到map中。
- 定义int变量count,用来统计 a+b+c+d = 0 出现的次数。
- 在遍历大C和大D数组,找到如果 0-(c+d) 在map中出现过的话,就用count把map中key对应的value也就是出现次数统计出来。
- 最后返回统计值 count 就可以了
class Solution {
public int fourSumCount(int[] nums1, int[] nums2, int[] nums3, int[] nums4) {
int res = 0;
Map<Integer,Integer> map = new HashMap();
for(int i = 0; i < nums1.length; i++){
for(int j = 0; j < nums2.length; j++){
int temp = nums1[i] + nums2[j];
if(map.containsKey(temp)){
map.replace(temp,map.get(temp),map.get(temp)+1);
}else{
map.put(temp,1);
}
}
}
for(int i = 0; i < nums3.length; i++){
for(int j = 0; j < nums4.length; j++){
int temp = -(nums3[i] + nums4[j]);
if(map.containsKey(temp)){
res += map.get(temp);
}
}
}
return res;
}
}
赎金信
题目链接:383. 赎金信
注意点:最后判断条件应该是record[i] > 0,因为magazine中的字母多出现是可以的。
class Solution {
public boolean canConstruct(String ransomNote, String magazine) {
int len1 = ransomNote.length();
int len2 = magazine.length();
if(len1 > len2){
return false;
}
int[] record = new int[26];
for(int i = 0; i < len1; i++){
record[ransomNote.charAt(i) - 'a'] += 1;
}
for(int i = 0; i < len2; i++){
record[magazine.charAt(i) - 'a'] -= 1;
}
for(int i = 0; i < record.length; i++){
if(record[i] > 0){
return false;
}
}
return true;
}
}
三数之和
题目链接:15. 三数之和
首先将数组排序,然后有一层for循环,i从下标0的地方开始,同时定一个下标left 定义在i+1的位置上,定义下标right 在数组结尾的位置上。
依然还是在数组中找到 abc 使得a + b +c =0,我们这里相当于 a = nums[i],b = nums[left],c = nums[right]。
接下来如何移动left 和right呢, 如果nums[i] + nums[left] + nums[right] > 0 就说明 此时三数之和大了,因为数组是排序后了,所以right下标就应该向左移动,这样才能让三数之和小一些。
如果 nums[i] + nums[left] + nums[right] < 0 说明 此时 三数之和小了,left 就向右移动,才能让三数之和大一些,直到left与right相遇为止。
通过Arrays.asList(nums[i],nums[left],nums[right])方法可以直接将数组转换为集合
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++){
// 如果第一个数就大于0,必然不符合
if(nums[0] > 0){
return res;
}
// 对nums[i]进行去重
if(i > 0 && nums[i] == nums[i-1]){
continue;
}
// 定义left和right指针
int left = i + 1;
int right = nums.length - 1;
// 当两个指针没有相遇时
while(left < right){
int sum = nums[i] + nums[left] + nums[right];
if(sum > 0){
right--;
}else if(sum < 0){
left++;
}else{
// 先收集这个三元组
res.add(Arrays.asList(nums[i],nums[left],nums[right]));
// 对nums[left]和nums[right]去重
while(left < right && nums[left+1] == nums[left]){
left++;
}
while(left < right && nums[right-1] == nums[right]){
right--;
}
// 在sum=0的情况下,不断的要移动left和right指针
left++;
right--;
}
}
}
return res;
}
}
四数之和
题目链接:18. 四数之和
主要理解剪枝和去重操作,在三数之和的基础上再嵌套一层。
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] > target && nums[i] > 0) {
return res;
}
//一级去重
if (i > 0 && nums[i] == nums[i - 1]) {
continue;
}
for (int j = i + 1; j < nums.length; j++) {
//二级剪枝
if (nums[i] + nums[j] > target && nums[i] > 0) {
return res;
}
//二级去重
if (j > i + 1 && nums[j] == nums[j - 1]){
continue;
}
//定义两个指针
int left = j + 1;
int right = nums.length - 1;
while (left < right){
//需要做一个强制转换,防止原先四个int相加超出int范围
long sum = (long) nums[i] + nums[j] + nums[left] + nums[right];
if (sum > target){
right--;
} else if (sum < target) {
left++;
}else {
res.add(Arrays.asList(nums[i],nums[j],nums[left],nums[right]));
while (left < right && nums[left] == nums[left + 1]){
left++;
}
while (left < right && nums[right] == nums[right - 1]){
right--;
}
left++;
right--;
}
}
}
}
return res;
}