赎金信

link:383. 赎金信 - 力扣(LeetCode)

思路分析

关键分析觉得是次数统计,ransomNote中的字符出现次数和magazine中统计次数相同即可.(有点相同字母异序词的味->哈希数组实现【大小写转换】)
题目又说是两个字符串全为小写字母,有数量限制(少量).方便进行映射.
可以暴力两层for循环求解,但又想到先前接触的哈希map进行映射.

Tip

本题目使用map消耗的空间资源比数组大一些.map要维护红黑树或哈希表还要做哈希函数,更费时.【数据量大时更能体现】

数组
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class Solution {
public boolean canConstruct(String ransomNote, String magazine) {
//创建需要的数组和中间汴梁
int[] arr = new int[26];
int tmp = 0;
//遍历rans 在magazine中映射确定 下标位置标记逐增
for(int i = 0; i < magazine.length(); i++) {
tmp = magazine.charAt(i) - 'a';
arr[tmp]++;
}
//在magazine中对应查找 找的的位置逐减
for(int i = 0 ;i < ransomNote.length(); i++) {
tmp = ransomNote.charAt(i) - 'a';
//注意情况判断
if(arr[tmp] > 0) {
arr[tmp]--;
}else {
return false;
}
}
return true;
}
}

三数之和

link:15. 三数之和 - 力扣(LeetCode)

思路分析

最先想的是两两分组,用数组做,然后又想到用哈希map映射,但是题目限制了去重,不是很好操作.
根据提供的示例发现只是三元组不能重复但是组内元素可以相同如[0,0,0].这种情况在去重的时候要考虑进去.避免对{-2,-2,4}这样的数据筛查遗漏.
所以判断条件是

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

而不是

1
if(nums[i] == nums[i + 1])

用双指针进行判断【必须是数组排好序】,i在数组起始位置,left在i+1位置,right在数组末尾.i和right先不动,left依次向后遍历,如果三者相加大于0,right向前移动.三折相加小于0,left往后移动.

Tip

三数去重碰到相邻相同元素进行跳过,因为已经判断过一次没必要再判断一次,还要进行减枝避免超时.

双指针
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
class Solution {
public List<List<Integer>> threeSum(int[] nums) {
//创建需要的有序列表
List<List<Integer>> res = new ArrayList<>();
Arrays.sort(nums);
//进行遍历判断 全大于0不可能加和为0
for(int i = 0; i < nums.length; i++) {
if(nums[i] > 0) {
return res;
}
//去重a、b
if(i > 0 && nums[i] == nums[i -1]) {
continue;
}
//双指针
int left = i + 1;
int right = nums.length - 1;
while(right > left) {
int sum = nums[i] + nums[left] + nums[right];
if(sum < 0){
left++;
}else if(sum > 0) {
right--;
}else {
res.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 res;
}
}