我都准备开始双指针那一节了,才发现双指针里面的内容大多还是前面以及后面章节的内容,比如链表里面的,有些已经做过了,但仔细一看,还存在哈希表的内容,就发觉我忘了一部分,,,哈希表那一节的题,不过剩下的哈希表的题也不是很难,理解了之后,还算简单,虽然看起来挺多的。
349两个数组交集
题目太多,直接分析之后贴代码。
在这总结的时候我想起来一件事,就是怎么去除重复的,一时间忘记了当时的想法,刚刚去查了一下,set是复用的hashmap的contains()方法,hashmap是不允许有重复的key值出现的,所以这也保证了我们得到的set2中不会有重复的值。
class Solution {
public int[] intersection(int[] nums1, int[] nums2) {
if(nums1 == null || nums1.length == 0 || nums2 == null || nums2.length == 0)
return new int[0];
Set<Integer> set1 = new HashSet<>();
Set<Integer> set2 = new HashSet<>();
for(int i : nums1)
set1.add(i);
for(int i : nums2){
if(set1.contains(i))
set2.add(i);//set1是否出现过,出现过就添加
}
int res[] = new int[set2.size()];
int count = 0;
for(int i : set2) {//set转化为数组
res[count] = i;
count++;
}
return res;
}
}
350题题目给的有点乱,其实就是结果返回重复值,这个重复值还可以重复存在并输出,所以map的设置是用来存放出现的值及次数,res数组来存放要返回的元组,先存好一个nums,然后再去比较,存在就count数减一(跟另一个比,存在就减少一个,减少到0,代表不再有这个key了)。同时,要是存在重复值,就把这个值存在res数组中。
class Solution {
public int[] intersect(int[] nums1, int[] nums2) {
if(nums1.length > nums2.length)
return intersect(nums2, nums1);
Map<Integer,Integer> map = new HashMap<>();
for(int i : nums1) {
int count = map.getOrDefault(i, 0) + 1;
map.put(i, count);
}
int res[] = new int[nums1.length];
int index = 0;
for(int i : nums2){//这里的i不是下标,而是nums2的值
int count2 = map.getOrDefault(i, 0);//判断map中是否存在key,存在返回value(这里的count)
if(count2 > 0) {//map里面含有这个值,有重复值出现
res[index] = i;//赶快存进这个数组
index++;
count2--;
if(count2 > 0)
map.put(i, count2);
else
map.remove(i);
}
}
return Arrays.copyOfRange(res, 0, index);//nums1为943,,但重复数字只有2个时,第三个就会初始化为0,输出940
// return res;
}
202快乐数
快乐数的难点在于数位分离,做好数位分离。分析题目,就是这个数最后可以变为1就是快乐数。通过不停的循环,看最后是否变为1,而支持这个循环的就是数位分离操作。可以看示例,来一步步操作。
class Solution {
public boolean isHappy(int n) {
Set<Integer> set = new HashSet<>();
while(n != 1 && !set.contains(n)){
set.add(n);
n = getNext(n);
}
return n == 1;
}
public int getNext(int n){//数位分离
int total = 0;
while(n > 0){
int d = n % 10;
n = n / 10;
total += d * d;
}
return total;
}
}
1.两数之和
这里使用map的原因就是他说要返回下标,所以我们要用map来存值和下标。
同时做这个题不能被局限的就是,,和—>减。后面几个求和也会用到。
class Solution {
public int[] twoSum(int[] nums, int target) {
if(nums == null || nums.length == 0)
return new int[2];
HashMap<Integer, Integer> map = new HashMap<>();//key存值,value存下标
int res[] = new int[2];
for(int i = 0; i < nums.length; i++){
int temp = target - nums[i];
if(map.containsKey(temp)){
res[0] = i;//题目说顺序无所谓
res[1] = map.get(temp);//获取temp这个key对应的value值(也就是下标)
}
map.put(nums[i], i);
}
return res;
}
}
四数相加在于,不需要考虑数值是否存在重复的情况,因为有四个数组,就随意搭配,搭配到能出现和为0的情况,然后记录下来次数,最后返回的也是次数(一个int)。做过前面的题,就可以知道,和也是减,所以利用这个想法去求解。
class Solution {
public int fourSumCount(int[] nums1, int[] nums2, int[] nums3, int[] nums4) {
Map<Integer, Integer> map = new HashMap<>();//key存放两数之和,value计算两数之和出现的次数
for(int i : nums1){
for(int j : nums2){
if(map.containsKey(i+j))
map.put(i+j, map.get(i+j) + 1);//相同的和再次出现就加一
else
map.put(i+j, 1);
}
}
//计算剩下两数之和,在map中寻找是否存在相加为0的情况
int res = 0;//计算元组的次数
for(int m : nums3){
for(int n: nums4){
int temp = 0 - (m+n);
if(map.containsKey(temp))
res += map.get(temp);
}
}
return res;
}
}
三数之和,四数之和,难点在于,不包含重复的四元组,最后返回的也是四元组。这里也是用的和即是减,但没有用哈希表,而是双指针,所以这个题也属于双指针系列。通过不停的的双指针:left和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++){
if(nums[i] > 0) return res;
if(i > 0 && nums[i] == nums[i-1]) continue;//排除移动i的时候,出现重复值的情况
int left = i + 1;
int right = nums.length - 1;
while(right > left){
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]));
while(left < right && nums[right] == nums[right-1]) right--;//去掉重复的值,前面排好序了
while(left < right && nums[left] == nums[left+1]) left++;
right--;//移动到下一位,进行下一轮i的匹配
left++;
}
}
}
return res;
}
}
四数之和(同理,五个数,六个数)
class Solution {
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(i > 0 && nums[i] == nums[i-1]) continue;
for(int j = i+1; j < nums.length; j++){
if(j > i+1 && nums[j] == nums[j-1]) continue;
int left = j + 1;
int right = nums.length - 1;
while(left < right){
int temp = nums[left] + nums[right] + nums[i] + nums[j];
if(temp > target) right--;
else if(temp < 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--;
right--;
left++;
}
}
}
}
return res;
}
}