什么时候使用哈希法?
当我们需要查询一个元素是否出现过,或者一个元素是否在集合里的时候,就要第一时间想到哈希法。
454.四数相加II
思路
- 哈希法
- Map
代码
class Solution {
public int fourSumCount(int[] nums1, int[] nums2, int[] nums3, int[] nums4) {
Map<Integer,Integer> map = new HashMap<>();
int res = 0;
for(int i = 0 ;i < nums1.length ;i++){
for(int j = 0; j<nums2.length;j++){
map.put(nums1[i]+nums2[j],map.getOrDefault(nums1[i]+nums2[j],0)+1);//统计 sum 出现的次数。
}
}
for(int i = 0; i<nums3.length;i++){
for (int j = 0;j<nums4.length;j++){
int tmp = -(nums3[i]+nums4[j]);
if(map.containsKey(tmp)){
res= res+map.getOrDefault(tmp,0);
}
}
}
return res;
}
}
复杂度
时间复杂度: O(n^2)
空间复杂度: O(n^2),最坏情况下A和B的值各不相同,相加产生的数字个数为 n^2
383. 赎金信
本题 和 242.有效的字母异位词 是一个思路 ,算是拓展题
思路
如果哈希值比较少、特别分散、跨度非常大,使用数组就造成空间的极大浪费
- 哈希表
- 数组
代码
import java.util.HashSet;
import java.util.Set;
class Solution {
class Solution {
public boolean canConstruct(String ransomNote, String magazine) {
int[] arr = new int[26];
for(int i = 0 ; i < ransomNote.length() ; i++){//--,++顺序想想
arr[ransomNote.charAt(i)-'a']--;
}
for(int j = 0 ; j< magazine.length();j++){
arr[magazine.charAt(j)-'a']++;
}
for(int k:arr){
if(k<0){//蛮巧妙
return false;
}
}
return true;
}
}
时间复杂度: O(n)
空间复杂度: O(1)
15. 三数之和
思路
- 不允许重复,去重(剪枝)
- 双指针法
代码
class Solution {
public List<List<Integer>> threeSum(int[] nums) {
List<List<Integer>> result = new ArrayList<> ();
Arrays.sort(nums);
for(int i = 0; i < nums.length; i++){
int a = nums[i];
if(a > 0){
return result;
}
if(i > 0 && nums[i] == nums[i-1]){
continue;
}
int left = i + 1;
int right = nums.length - 1;
while(left < right){
if(a + nums[left] + nums[right] > 0) {right--;}
else if(a + nums[left] + nums[right] < 0){left++;}
else {
result.add(Arrays.asList(nums[i],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 result;
}
}
18. 四数之和
思路
- 哈希法
- 双指针法(与15相似)
代码
class Solution {
public List<List<Integer>> fourSum(int[] nums, int target) {
Arrays.sort(nums);
List<List<Integer>> result = new ArrayList<>();
for(int k = 0; k < nums.length; k++){
if(nums[k] > 0 && nums[k] > target){//注意判断条件
return result;
}
int a = nums[k];
if(k > 0 && nums[k] == nums[k-1]){//又忘了剪枝
continue;
}
for(int i = k + 1; i < nums.length; i++){
int b = nums[i];
if(i > k + 1 && b == nums[i - 1]){//也忘记剪枝
continue;
}
int sum1 = a + b;
int left = i + 1;//一开始写成i+k+1
int right = nums.length - 1;
while(left < right ){//判断条件我一开始写了target>0
int sum2 = nums[left] + nums[right];
long sum = (long) nums[i] + nums[k] + nums[left] + nums[right];
//使用了 (long) 强制类型转换,将四个 int 类型的整数相加后,再赋值给 long 类型的变量 sum。这种处理是为了避免在计算过程中发生整数溢出。
if(sum > target){
right --;
}
else if(sum < target){
left++;
}
else{result.add(Arrays.asList(nums[k],nums[i],nums[left],nums[right]));//语句又搞错了;使用了 (long) 强制类型转换,将四个 int 类型的整数相加后,再赋值给 long 类型的变量 sum。这种处理是为了避免在计算过程中发生整数溢出。
while(left < right && nums[left] == nums[left+1]){left++;}
while(left > right && nums[right] == nums[right - 1]){right--;}
right--;
left++;//剪枝在判断了这组=target,再来判断
}
}
}
}
return result;
}
}
复杂度
时间复杂度: O(n^3)
空间复杂度: O(1)