1,快速排序
class Solution {
public:
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
* 将给定数组排序
* @param arr int整型vector 待排序的数组
* @return int整型vector
*/
void quickSort(vector<int>& arr, int left, int right) {
// 定界
if (left >= right) {
return;
}
int i = left, j = right;
int base = arr[left];
while (i < j) {
while((i < j) && (arr[j] >= base)) {
j--;
}
while((i < j) && (arr[i] <= base)) {
i++;
}
if (i < j) {
swap(arr[i], arr[j]);
}
}
arr[left] = arr[i];
arr[i] = base;
quickSort(arr, left, i - 1);
quickSort(arr, i + 1, right);
}
vector<int> MySort(vector<int>& arr) {
int len = arr.size();
if (len == 0) {
return arr;
}
quickSort(arr, 0, len - 1);
return arr;
}
};
2,数组的归并排序
class Solution {
public:
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
* 将给定数组排序
* @param arr int整型vector 待排序的数组
* @return int整型vector
归并排序
*/
void merge(int left, int mid, int right, vector<int>& arr) {
int i = left, j = mid + 1;
int k = 0;
vector<int>temp(right - left + 1, 0);
while(i <= mid && j <= right) {
if (arr[i] < arr[j]) {
temp[k++] = arr[i++];
} else {
temp[k++] = arr[j++];
}
}
while(i <= mid) {
temp[k++] = arr[i++];
}
while(j <= right) {
temp[k++] = arr[j++];
}
int index = 0;
for(int i = left; i <= right; i++) {
arr[i] = temp[index++];
}
}
void guibing(int left, int right, vector<int>& arr) {
if (left >= right) {
return;
}
int mid = (left + right) / 2;
guibing(left, mid, arr);
guibing(mid + 1, right, arr);
merge(left, mid, right, arr);
}
vector<int> MySort(vector<int>& arr) {
guibing(0, arr.size() - 1, arr);
return arr;
}
};
3,链表的归并排序
https://www.nowcoder.com/practice/f23604257af94d939848729b1a5cda08
/**
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
class Solution {
public:
/**
*
* @param head ListNode类 the head node
* @return ListNode类
*/
ListNode* sortInList(ListNode* head) {
if (!head || !head->next) {
return head;
}
ListNode* mid = getMid(head);
ListNode *left = sortInList(head);
ListNode *right = sortInList(mid);
return Merge(left, right);
}
ListNode* getMid(ListNode* head) {
if(!head) {
return head;
}
ListNode* fast = head, *slow = head;
ListNode* prev = slow;
while(fast && fast->next) {
prev = slow;
slow = slow->next;
fast = fast->next->next;
}
prev->next = nullptr; // 切断mid和之前的联系,mid属于后面
return slow;
}
ListNode *Merge(ListNode *l1, ListNode *l2) {
if (!l1) {
l2;
}
if (!l2) {
l1;
}
ListNode *head = new ListNode(-1);
ListNode *ret = head;
while(l1 && l2) {
if (l1->val < l2->val) {
ret->next = new ListNode(l1->val);
l1 = l1->next;
} else {
ret->next = new ListNode(l2->val);
l2 = l2->next;
}
ret = ret->next;
}
if (l1) {
ret->next = l1;
}
if (l2) {
ret->next = l2;
}
return head->next;
}
};
4,寻找第K大
使用快速排序,利用左面的都比base小,右面的都比base大这件事。
class Solution {
public:
int findKth(vector<int> a, int n, int K) {
return quickfind(a, 0, n-1, K);
}
int quickfind(vector<int>& a, int left, int right, int k) {
int i = left;
int j = right;
int mark = a[left];
while (i < j) {
while (i < j && a[j] >= mark)
--j;
while (i < j && a[i] <= mark)
++i;
if (i < j) {
int temp = a[i];
a[i] = a[j];
a[j] = temp;
}
}
a[left] = a[i];
a[i] = mark;
//哨兵右侧比他大的数字个数
int big_num = right - i;
//如果哨兵刚好是第K大的数
if (k - big_num - 1 == 0)
return mark;
else if (k - big_num - 1 > 0) {
//如果右侧数字个数不够K个,则从左侧找第k-big_num-1大的数
return quickfind(a, left, i - 1, k - big_num - 1);
} else {
//如果右侧数字个数比K多,则在右侧找第K大的数
return quickfind(a, i + 1, right, k);
}
}
};
5,NC41 最长无重复子数组
![在这里插入图片描述](https://img-blog.csdnimg.cn/f7c89f0085b5449699ca74637c65fa40.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBA5aaC5p6c5aSp56m65LiN5q27LXNreSB3YW5n,size_16,color_FFFFFF,t_70,g_se,x_16)
class Solution {
public:
/**
*
* @param arr int整型vector the array
* @return int整型
*/
/*
最长无重复子数组
1,使用map记录数组中各个元素出现位置
2, 若遇到重复的, 找到之前最近的一个重复的值,记为index
3,index+1(认为是start)~i的距离是ret的候选人,不断更新最大值。
ret = max(ret, [index + 1, i])
*/
int maxLength(vector<int>& arr) {
// write code here
int len = arr.size();
int ret = 0, start = 0;
map<int, int>mp;
for (int i = 0; i < len; i++) {
// 如果找到重复的,开始刷新ret
if(mp.find(arr[i]) != mp.end()) {
start = max(start, mp[arr[i]] + 1);
}
ret = max(ret, i - start + 1);
// 更新位置
mp[arr[i]] = i;
}
return ret;
}
};
6,字符串出现次数的topK问题
![在这里插入图片描述](https://img-blog.csdnimg.cn/4e0ffcea99d1480a8f06f1668e9fc2ec.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBA5aaC5p6c5aSp56m65LiN5q27LXNreSB3YW5n,size_12,color_FFFFFF,t_70,g_se,x_16)
class Solution {
public:
/**
* return topK string
* @param strings string字符串vector strings
* @param k int整型 the k
* @return string字符串vector<vector<>>
*/
/*
使用map记录每个字符串出现的次数
将map的东西放在vector中,对vec进行排序和输出,重点是比较功能
*/
static bool cmp(vector<string> &a, vector<string> &b) {
if (a[1] == b[1]) {
return a[0] < b[0];
}
return stoi(a[1]) > stoi(b[1]);
}
vector<vector<string> > topKstrings(vector<string>& strings, int k) {
// write code here
int len = strings.size();
map<string, int>mp;
// 1, 将数据记录到map中
for (int i = 0; i < len; i++) {
mp[strings[i]]++;
}
map<string, int>::iterator it = mp.begin();
vector<vector<string>> ret;
// 2, 将数据记录到vector中
for (; it != mp.end(); it++) {
ret.push_back({it->first, to_string(it->second)});
}
// 3,比较
sort(ret.begin(), ret.end(), cmp);
ret.resize(k);
return ret;
}
};
7,未排序数组中累加和为给定值的数组最大长度
![在这里插入图片描述](https://img-blog.csdnimg.cn/fb116bac75e34912a6872943eda2f512.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBA5aaC5p6c5aSp56m65LiN5q27LXNreSB3YW5n,size_15,color_FFFFFF,t_70,g_se,x_16)
class Solution {
public:
/**
* max length of the subarray sum = k
* @param arr int整型vector the array
* @param k int整型 target
* @return int整型
*/
/*
遍历arr,S(i) 表示arr[0, i]的和,使用map记录这些前缀和。
S(j)表示从[0,j]的前缀和
若s[i] - s[j] = target,那么[i + 1, j]就是候选人之一,使用ret不断刷新。
为了防止漏掉0, mp插入(0,-1)。
*/
int maxlenEqualK(vector<int>& arr, int k) {
int len = arr.size();
map<int, int>mp;
int sum = 0;
int ret = 0;
mp[0] = -1;
for (int i = 0; i < len; i++) {
sum += arr[i];
// 在mp中寻找s(i)
if (mp.find(sum) == mp.end()) {
mp[sum] = i;
}
if (mp.find(sum - k) != mp.end()) {
ret = max(ret, i - mp[sum - k]);
}
}
return ret;
}
};
8,信封嵌套问题
![在这里插入图片描述](https://img-blog.csdnimg.cn/4949c2fed0324573b94f846c385e22ec.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBA5aaC5p6c5aSp56m65LiN5q27LXNreSB3YW5n,size_15,color_FFFFFF,t_70,g_se,x_16)
class Solution {
public:
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param letters intvector<vector<>>
* @return int
*/
/*
二维问题是信封嵌套,一维问题就是一个数组中最长递增子序列是多少。
如何将二维问题转化成一维问题呢?
信封=长X宽。
1,先对长进行递增排序,若长相等的,宽度要递减排序
所以从后遍历,若宽度>前面的,表示后面可以嵌套前面的。
*/
static bool cmp(vector<int> &a, vector<int> &b) {
if (a[0] == b[0]) {
return a[1] > b[1];
}
return a[0] < b[0];
}
int maxLetters(vector<vector<int> >& letters) {
// write code here
// 对输入进行判断
if(letters.size() == 0) {
return 0;
}
int len = letters.size();
sort(letters.begin(), letters.end(), cmp);
vector<int>dp(len, 1);
int ret = 1;
for (int i = 1; i < len; i++) {
for (int j = 0; j < i; j++) {
if (letters[i][1] > letters[j][1]) {
dp[i] = max(dp[i], dp[j] + 1);
}
ret = max (ret, dp[i]);
}
}
return ret;
}
};
9,信封嵌套问题
![在这里插入图片描述](https://img-blog.csdnimg.cn/690f702fb00646478851f4edf56cfff7.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBA5aaC5p6c5aSp56m65LiN5q27LXNreSB3YW5n,size_10,color_FFFFFF,t_70,g_se,x_16)
层次遍历
打印Z字形
右视图
寻找next
这四种都是层次遍历的变形。
/*
// Definition for a Node.
class Node {
public:
int val;
Node* left;
Node* right;
Node* next;
Node() : val(0), left(NULL), right(NULL), next(NULL) {}
Node(int _val) : val(_val), left(NULL), right(NULL), next(NULL) {}
Node(int _val, Node* _left, Node* _right, Node* _next)
: val(_val), left(_left), right(_right), next(_next) {}
};
*/
/*
层次遍历,设置pre和curr节点
*/
class Solution {
public:
Node* connect(Node* root) {
if(!root) {
return root;
}
queue<Node*> que;
que.push(root);
Node *preNode, *currNode;
while(!que.empty()) {
int size = que.size();
int cnt = 0;
while(cnt < size) {
if (cnt == 0) {
preNode = currNode = que.front();
que.pop();
} else {
currNode = que.front();
que.pop();
preNode->next = currNode;
preNode = preNode->next;
}
if (currNode->left) {
que.push(currNode->left);
}
if (currNode->right) {
que.push(currNode->right);
}
cnt++;
}
}
return root;
}
};
9,560. 和为 K 的子数组
![在这里插入图片描述](https://img-blog.csdnimg.cn/be5a6284da874c21ab50f4ac5a5e1f12.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBA5aaC5p6c5aSp56m65LiN5q27LXNreSB3YW5n,size_12,color_FFFFFF,t_70,g_se,x_16)
class Solution {
public:
int subarraySum(vector<int>& nums, int k) {
/*
map<sum, vector<int>>; --map<int, int就可以
表示vector<i>之前的,包括i,和为sum
遍历到i
看map<i - k>是否存在,
如果存在
cnt + map[i-k]
*/
int len = nums.size();
if (len == 0) {
return 0;
}
int ret = 0, sum = 0;
map<int, int>mp;
mp[0] = 1;
for (int i = 0; i < nums.size(); i++) {
sum += nums[i];
if (mp.find(sum - k) != mp.end()) {
ret += mp[sum - k];
}
mp[sum]++;
}
return ret;
}
};
10,297. 二叉树的序列化与反序列化
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
/*
序列化和反序列化
序列化:
前序遍历,遇到空的string后面添加“NULL,”,其他数字加“,”
反序列化:
将上面的string 拆解在list中
list<string>list
然后开始反序列化,遇到NULL,擦除list的头部+返回nullptr
开始左右递归。
*/
class Codec {
public:
void reserialize(TreeNode *root, string &data) {
if (!root) {
data += "NULL,";
return;
}
data += to_string(root->val) + ",";
reserialize(root->left, data);
reserialize(root->right, data);
}
// Encodes a tree to a single string.
string serialize(TreeNode* root) {
string ret;
reserialize(root, ret);
return ret;
}
TreeNode* redeserialize(list<string> &arr) {
if (arr.front() == "NULL") {
arr.erase(arr.begin());
return nullptr;
}
TreeNode *root = new TreeNode(stoi(arr.front()));
arr.erase(arr.begin());
root->left = redeserialize(arr);
root->right = redeserialize(arr);
return root;
}
// Decodes your encoded data to tree.
TreeNode* deserialize(string data) {
int len = data.size();
if (len == 0) {
return nullptr;
}
string str;
list<string> dataArr;
for (int i = 0; i < data.size(); i++) {
if (data[i] == ',') {
dataArr.push_back(str);
str.clear();
} else {
str += data[i];
}
}
if (!str.empty()) {
dataArr.push_back(str);
}
return redeserialize(dataArr);
}
};
// Your Codec object will be instantiated and called as such:
// Codec ser, deser;
// TreeNode* ans = deser.deserialize(ser.serialize(root));
11,253. 会议室 II
class Solution {
public:
static bool cmp(vector<int> &a, vector<int> &b) {
if (a[0] == b[0]) {
return a[1] > b[1];
}
return a[0] < b[0];
}
int minMeetingRooms(vector<vector<int>>& intervals) {
/*
按照会议开始时间升序排列,
if(当前开始时间 > 上一个结束时间) {
pq pop// 因为当前和上面是可以共用的
将当前开始时间push到队列中
} else {
将当前开始时间push到队列中
}
return pq.size();
*/
int len = intervals.size();
if (len == 0 || len == 1) {
return len;
}
sort (intervals.begin(), intervals.end(), cmp);
priority_queue<int, vector<int>, greater<int>> pq;
pq.push(intervals[0][1]);
int ret = 1;
for (int i = 1; i < len; i++) {
if (intervals[i][0] >= pq.top()) {
pq.pop();
}
pq.push(intervals[i][1]);
}
return pq.size();
}
};
12,994. 腐烂的橘子
![在这里插入图片描述](https://img-blog.csdnimg.cn/0d6885ab87234787a4113971aa046550.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBA5aaC5p6c5aSp56m65LiN5q27LXNreSB3YW5n,size_11,color_FFFFFF,t_70,g_se,x_16)
class Solution {
public:
int orangesRotting(vector<vector<int>>& grid) {
if (grid.size() == 0) {
return 0;
}
// 1, 遍历当前数组中的腐烂句子
for (int i = 0; i < grid.size(); ++i) {
for (int j = 0; j < grid[i].size(); ++j) {
if (grid[i][j] == 2)
dfs(grid, i, j, 2);
}
}
// 2, 计算形成最后的画面需要的最长时间
int maxTime = 0;
for (int i = 0; i < grid.size(); ++i) {
for (int j = 0; j < grid[i].size(); ++j) {
if (grid[i][j] == 1) {
return -1;
} else {
maxTime = max(maxTime, grid[i][j]);
}
}
}
return maxTime == 0 ? 0 : maxTime - 2;
}
void dfs(vector<vector<int>>& grid, int x, int y, int time) {
// 基本定界
if (x < 0 || x >= grid.size() || y < 0 || y >= grid[0].size()) {
return;
}
// 如果grid不是新鲜橘子而且到这里腐烂的时间<time,说明之前已经遍历过了
if (grid[x][y] != 1 && grid[x][y] < time) {
return;
}
grid[x][y] = time;
dfs(grid, x + 1, y, time + 1);
dfs(grid, x - 1, y, time + 1);
dfs(grid, x, y + 1, time + 1);
dfs(grid, x, y - 1, time + 1);
}
};
13,128. 最长连续序列
![在这里插入图片描述](https://img-blog.csdnimg.cn/f3bf113240d94fd39086d1b3f2278866.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBA5aaC5p6c5aSp56m65LiN5q27LXNreSB3YW5n,size_11,color_FFFFFF,t_70,g_se,x_16)
class Solution {
public:
int longestConsecutive(vector<int>& nums) {
if(nums.empty()){
return 0;
}
unordered_set<int> myset(nums.begin(), nums.end());
int res = 0;
for(auto num : nums){
if(myset.count(num-1)==0){
int x = num + 1;
while(myset.count(x)){
x ++;
}
res = max(res, x-num);
}
}
return res;
}
};
14,49. 字母异位词分组
![在这里插入图片描述](https://img-blog.csdnimg.cn/548483c004754623a9af487a93827224.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBA5aaC5p6c5aSp56m65LiN5q27LXNreSB3YW5n,size_11,color_FFFFFF,t_70,g_se,x_16)
class Solution {
public:
vector<vector<string>> groupAnagrams(vector<string>& strs) {
vector<vector<string>>ret;
map<string, vector<string>>mp;
for (auto n : strs) {
auto temp = n;
sort(temp.begin(), temp.end());
mp[temp].push_back(n);
}
for(auto n : mp) {
ret.push_back(n.second);
}
return ret;
}
};
15,3. 无重复字符的最长子串
![在这里插入图片描述](https://img-blog.csdnimg.cn/888f6628094347678a7e58e1bce01f25.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBA5aaC5p6c5aSp56m65LiN5q27LXNreSB3YW5n,size_10,color_FFFFFF,t_70,g_se,x_16)
class Solution {
public:
/*
以当前数字为起始位置的最长子串
*/
int lengthOfLongestSubstring(string s) {
int len = s.size();
if(len == 0 || len == 1) {
return len;
}
int ret = 0;
for (int i = 0; i < len; i++) {
map<char, int>mp;
int cnt = 0;
for (int j = i; j < len; j++) {
if (mp.find(s[j]) == mp.end()) {
mp[s[j]]++;
cnt++;
} else {
break;
}
ret = max (ret, cnt);
}
}
return ret;
}
};
16,面试题 16.25. LRU 缓存
![在这里插入图片描述](https://img-blog.csdnimg.cn/50a875b2801848899edeb30a05b96bf3.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBA5aaC5p6c5aSp56m65LiN5q27LXNreSB3YW5n,size_10,color_FFFFFF,t_70,g_se,x_16)
class LRUCache {
public:
map<int,int> mp, vis; // 使用map存储键值 + 版本号机制
queue<pair<int,int>> que;
int cnt, cap, currSize;
LRUCache(int capacity) {
cap = capacity; // 容量
cnt = 0; // 用来位置版本号
currSize = 0; // 当前缓存的个数
}
int get(int key) {
// 如果在visited中找不到key, return -1
if (vis[key] == 0) {
return -1;
}
// 一把更新,cnt用来维持版本号,保证每次版本号都不同
que.push({key, vis[key] = ++ cnt});
return mp[key];
}
void put(int key, int value) {
// 如果当前的版本号和现在的版本号一样,说明没有被操作过,也就是最久没有被访问过的,需要被pop
if(!vis[key]){
while(currSize == cap){
auto front = que.front();
que.pop();
if(vis[front.first] == front.second){
// 这里是把它降为0,而不是erase
vis[front.first] = 0;
--currSize;
break;
}
}
++currSize;
}
mp[key]=value;
que.push({key,vis[key] =++cnt});
}
};
17,694. 不同岛屿的数量
![在这里插入图片描述](https://img-blog.csdnimg.cn/9df2f44914d14470821bbae80a0084ca.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBA5aaC5p6c5aSp56m65LiN5q27LXNreSB3YW5n,size_10,color_FFFFFF,t_70,g_se,x_16)
class Solution {
public:
/*
如何计算呢?
使用string计算路径。上下左右分布是1,2,3,4 反向分别是-1-2-3-4
set<string>st;
st.insert()
最终计算st.size();
1,使用string来表示对应的路径,还有回溯的思想,使用-dir表示已经回头。
2,使用set去重,因此set.size可以直接表示ret
*/
void dfs(vector<vector<int>>& grid, int x, int y, string &str, string dir) {
// 定界
if(x < 0 || x >= grid.size() || y < 0 || y >= grid[0].size()) {
return;
}
if (grid[x][y] == 0) {
return;
}
grid[x][y] = 0;
str += dir;
dfs(grid, x + 1, y, str, "1");
dfs(grid, x - 1, y, str, "2");
dfs(grid, x, y + 1, str, "3");
dfs(grid, x, y - 1, str, "4");
str += "-";
str += dir;
}
int numDistinctIslands(vector<vector<int>>& grid) {
int column = grid.size();
int line = grid[0].size();
set<string> st1;
for (int i = 0; i < column; i++) {
for (int j = 0; j < line; j++) {
if (grid[i][j] == 1) {
string str = "";
dfs(grid, i, j, str, "0");
cout << str << endl;
st1.insert(str);
}
}
}
return st1.size();
}
};
18,剑指 Offer 07. 重建二叉树
/**
* Definition for binary tree
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
unordered_map<int, int>mp;
public:
TreeNode* reConstructBinaryTree(vector<int> pre,vector<int> vin) {
int len = pre.size();
if (len == 0) {
return nullptr;
}
for (int i = 0; i < len; i++) {
mp[vin[i]] = i;
}
return dfs(pre, vin, 0, len - 1, 0, len - 1);
}
TreeNode * dfs(vector<int> pre,vector<int> vin, int preLeft, int preRight, int inLeft, int inRight) {
if (preLeft > preRight || inLeft > inRight) {
return nullptr;
}
// 获取pos
int pos = mp[pre[preLeft]];
TreeNode *root = new TreeNode(pre[preLeft]); // 左子树节点的个数为 pos - inLeft
root->left = dfs(pre, vin, preLeft + 1, preLeft + pos - inLeft, inLeft, pos - 1); // 注意pre的左子树应该去掉首值
root->right = dfs(pre, vin, preLeft + pos - inLeft + 1, preRight, pos + 1, inRight);
return root;
}
};