(•̀ᴗ•́)و 大二打算法的小菜狗又回来啦!这次是以研究生找工作的目标开始刷题,坚持就是胜利!每天一道,完成比完美更加重要!
这篇笔记会使用Java和C++两种语言去刷题~
目录
[1、两数之和 - 哈希表](#1、两数之和 - 哈希表)
[2、字母异位词分组 - 哈希表](#2、字母异位词分组 - 哈希表)
[3、最长连续序列 - 哈希表](#3、最长连续序列 - 哈希表)
[4、移动零 - 双指针](#4、移动零 - 双指针)
1、两数之和 - 哈希表
这道题很容易想到O(n2)的双for循环暴力破解,这里就不再赘述。
思路:每遍历到一个位置,开始查map:前面有没有人和我匹配?有就直接返回,没有就把自己登记到map中,继续往后寻找
用Map存【nums[i] : 下标i】,注意值为key,下标为value
这样遍历数组nums时,对于每一个nums[i]:
- 如果map中存在key = target - nums[i],说明当前数和前面的某个数之和恰好为target,直接返回[map(target-nums[i])下标,i]
- 否则将【nums[i]:i】存入map中,继续向后寻找
【1】Java版
java
class Solution {
public int[] twoSum(int[] nums, int target) {
Map<Integer,Integer> mp = new HashMap<>();
for(int i = 0;i < nums.length; i++){
if(mp.containsKey(target - nums[i]))
return new int[]{mp.get(target - nums[i]),i};
mp.put(nums[i],i);
}
throw new IllegalArgumentException("No two sum solution");
}
}
【2】C++版
cpp
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
unordered_map<int,int> mp;
for(int i=0;i<nums.size();i++){
if(mp.count(target - nums[i]))
return {mp[target - nums[i]],i};
mp[nums[i]]=i;
}
return {};
}
};
2、字母异位词分组 - 哈希表
题意:
如果两个字符串从小到大排序后相等,那么两个字符串就互为字母异位词,否则不是。
例如 aab,aba,baa 排序后都是 aab,所以 aab,aba,baa 互为字母异位词。
思路:用哈希表存储【key:排序后的字符串,value列表:排序前的字符串】
最后按key输出每组value值
【1】Java版
cpp
class Solution {
public List<List<String>> groupAnagrams(String[] strs) {
Map<String,List<String>> mp = new HashMap<>();
for(String s : strs){
char[] sorted = s.toCharArray();
Arrays.sort(sorted);
//- 如果map中不存在这个key,则创建一个新的空List作为value
//- 如果map中已存在这个key,则直接返回对应的value(已有的List)
//最后,将字符串s添加到这个(新的或已有的)List中
mp.computeIfAbsent(new String(sorted),_ -> new ArrayList<>()).add(s);
}
return new ArrayList<>(mp.values());
}
}
【2】C++版
cpp
class Solution {
public:
vector<vector<string>> groupAnagrams(vector<string>& strs) {
unordered_map<string,vector<string>> mp;
for(string& s:strs){
string sorted = s;
sort(sorted.begin(),sorted.end());
mp[sorted].push_back(s);
}
vector<vector<string>> res;
for (auto& pair : mp) {
res.push_back(pair.second);
}
return res;
}
};
3、最长连续序列 - 哈希表
我尝试排序sort,只跑通一半样例,想【0,1,1,2】这种情况最长序列个数为3(0,1,1)或(1,1,2),但我的代码计算这个样例时跑出来是(0,1,1,2),故放弃,看题解
题意:给定一个未排序的整数数组 nums ,找出数字连续的最长序列(不要求序列元素在原数组中连续)的长度。
请你设计并实现时间复杂度为 O(n) 的算法解决此问题。
0,1,1,2\] 答案:3 **思路**: 首先,本题是不能排序的,因为排序的时间复杂度是 O(nlogn),不符合题目 O(n) 的要求。 我们将数字存入set(去重),因为set可以快速判断元素是否存在set.contains() 核心思路:对于 nums 中的元素 x,以 x 为起点,不断查找下一个数 x+1,x+2,⋯ 是否在 nums 中,并统计序列的长度。 * 我们遍历set中的每一个元素x,对于每一个x,如果set中存在x-1,则跳过该x,因为后面以x-1为起点的序列肯定更长,避免重复计算 * 确定好起点x后,循环向后不断查找 y = x+1 是否在set中,如果存在则y++ * 循环结束后,y-1就是连续序列的最后一个数,则最长序列为【x \~ y-1】,长度为 y-x * 遍历每一个x都以其为起点(如果存在更小的以更小的为起点,避免重复计算),算出以它为起点的最长连续序列长度,最后通过res = max(res , y-x)维护全场最长序列长度
【1】Java版
cpp
class Solution {
public int longestConsecutive(int[] nums) {
Set<Integer> st = new HashSet<>();
for(int num: nums) st.add(num);
int res = 0;
for(int x: st){
if(st.contains(x - 1)) continue;
int y = x + 1;
while(st.contains(y)) y++;
res = Math.max(res, y - x);
}
return res;
}
}
【2】C++版
cpp
class Solution {
public:
int longestConsecutive(vector<int>& nums) {
int res = 0;
unordered_set<int> st(nums.begin(),nums.end());
for(int x: st){
if(st.contains(x-1)) continue;//如果序列中存在更小的,以更小的为起点
//找到最小的起点x
int y = x + 1;
while(st.contains(y)) y++; //不断向后查找下一个数是否在set
//循环结束后,y-1是最后一个在哈希表的数
res = max(res, y - x); //从x~y-1序列长度为y-x
}
return res;
}
};
4、移动零 - 双指针
题意:
给定一个数组
nums,编写一个函数将所有0移动到数组的末尾,同时保持非零元素的相对顺序。请注意 ,必须在不复制数组的情况下原地对数组进行操作。
输入: [0,1,0,3,12] 输出: [1,3,12,0,0]
思路:
最直接的思路是,把非零元素整体挪到最前面,零元素整体挪到最后面
我们可以维护下标【i0 ~ i-1】区间为零元素,a[i0]始终指向最靠左边的零元素
- 当i=n时循环结束,此时【i0 ~ n-1】即为零元素,即把零元素挪到最后
- 注:这里a[i0]始终在最左边,这样非零元素和a[i0]交换时始终在相对最前边,即保证非零元素原始顺序
遍历数组a,如果:
- a[i]=0,则不操作
- a[i]≠0,则交换swap(a[i],a[i0]),i0++
比如[0,1,0,3,12]:(绿色区间代表维护的【i0 ~ i-1】区间)
i=0 [++0++,1,0,3,12] 不操作 i0=0
i=1 [0,++1++,0,3,12] swap(a[i]=1,a[i0]=0) i0++(i0=1)
i=1 [++1,0++,0,3,12] 交换完
i=2 [1,0,++0++,3,12] 不操作 i0=1
i=3 [1,0,0,++3++,12] swap(a[i]=3,a[i0]=0) i0++(i0=2)
i=3 [1,++3++ ,0,++0++,12] 交换完
i=4 [1,3,0,0,++12++] swap(a[i]=12,a[i0]=0) i0++(i0=3)
i=4 [1,3,++12++,0,++0++] 交换完
i=5 [1,3,12,0,0] 遍历结束(i0=3)
【1】Java版
cpp
class Solution {
public void moveZeroes(int[] a) {
int i0=0;
for(int i=0;i<a.length;i++)
if(a[i]!=0)
{
int t=a[i];
a[i]=a[i0];
a[i0]=t;
i0++;
}
}
}
【2】C++版
cpp
class Solution {
public:
void moveZeroes(vector<int>& a) {
int i0 = 0;
for(int i = 0; i < a.size(); i++){
if(a[i]!=0){
swap(a[i],a[i0]);
i0++;
}
}
}
};
