string ans = strs[0];for(int i =1; i < strs.size();++i){// 每一轮迭代继承上一轮的公共最长子序列
string t = ans;
ans ="";for(int j =0; j < strs[i].size()&& j < t.size();++j)if(str[i][j]== t[j]) ans += t[j];if(ans =="")break;// 不可能的情况直接退出}
26 删除数组中重复项
int p =1;for(int i =1; i < nums.size();++i){if(nums[i]!= nums[i -1]){
nums[p]= nums[i];++p;}}return p;
for(int i = m + n -1; i >0;--i){// 考虑该判断式,一边结束后另一边数组继续if(m ==0|| n !=0&& num2[n -1]> num1[m -1]){
num1[i]= num2[n -1]; n--;}else{
num1[i]= num1[m -1]; m--;}}
118 杨辉三角
// 辅助数组保存位置记录
136 只出现一次数字,位运算抵消
for(int i =0; i < nums.size();++i){
ans ^= nums[i];}
贪心
53 最大子序列和
int ans = INT_MIN, now =0;for(int i =0; i < nums.size();++i){// now 保存之前连续子序列加和,若正可再加,负的话重新开始
now =min(nums[i], nums[i]+ now);
ans =max(ans, now);}
121 买卖股票1
int ans =0, mmin = prices[i];for(int i =1; i < prices.size();++i){// 每次更新扣除之前最小值可能获得的最大理论
ans =max(ans, prices[i]- mmin);
mmin =min(mmin, prices[i]);}
122 买卖股票2
// 只要后天股票价格比前天高就加for(int i =1; i < prices.size();++i){if(prices[i]> prices[i-1]){
ans += prices[i]- prices[i-1];}}
二分
278 0011情况
while(l != r){int mid =(l + r)/2;if(isBadVersion(mid)){
r = mid;// 右边可能}else{
l = mid +1;// 左边肯定不是}}// 输出 l r 位置均可
35 搜索插入位置 0011问题
while(l != r){int mid =(l + r)/2;if(nums[mid]>= target){
r = mid;}else{
l = mid +1;}}
69 平方根,保留整数,1100问题
longlong l =0, r = x;while(l != r){int mid =(l + r +1)/2;if(mid * mid <= x){
l = mid;}else{
r = mid -1;}}
递归,深度搜索
130 围绕区域改正,先深搜外围标记
// 需要边缘判断voidfunc(vector<vector<char>>& board,int x,int y){
board[x][y]='E';for(int i =0; i <4;++i){int xx = x + dir[i][0];int yy = y + dir[i][1];if(xx <0|| yy <0|| xx == n || yy == m || board[xx][yy]!='O')continue;func(board, xx, yy);}}// 先在边缘入口转化外围字符为 E 最后修改 O 为 X,E 为 O
200 岛屿连接数量,每个点深搜加标记
// 标记是否去过voidfunc(vector<vector<char>>& grid,int x,int y){for(int i =0; i <4;++i){int xx = x + dir[i][0];int yy = y + dir[i][1];if(xx <0|| yy <0|| xx == n || yy == m ){continue;}if(grid[xx][yy]=='1'&&!check[xx][yy]){
check[xx][yy]=1;func(grid, xx, yy);}}}// 遍历进入的时候起点 ans++
967 连续差相等的数字
// 推入现在数字为多少 ... k 也可以写在外面作为全局变量voidfunc(int now,int left,int k){// 剩余数字为0结束if(left ==0){
ans.push_back(now);return;}// 往上加数字 kif(now %10+ k <10){func(now *10+ now %10+ k, left -1, k);}// 往下 - 数字 kif(k !=0&& now %10- k >=0){func(now *10+ now %10- k, left -1, k);}}// 每个起点递归for(int i =1; i <10;++i){func(i, n -1, k);}
广度搜索
1091 记录到达目的最短步数
que.push((node){0,0,0});while(!que.empty()){
node temp = que.front();
que.pop();if(temp.x == n -1&& temp.y == n -1){return temp.step +1;}for(int i =0; i <8;++i){int x = temp.x + dir[i][0];int y = temp.y + dir[i][1];if(x <0|| y <0|| x == n || y == n)continue;if(grid[x][y]==0&&!check[x][y]){
check[x][y]=1;
que.push((node){x, y, temp.step +1});}}}
994 向外感染
// 可以不标记直接修改原数组,注意特判新鲜橘子数量int ans =0;while(!que.empty()){
node temp = que.front();
que.pop();for(int i =0; i <4;++i){int x = temp.x + dir[i][0];int y = temp.y + dir[i][1];if(x <0|| y <0|| x == n || y == m)continue;if(grid[x][y]==1){
grid[x][y]=2;
ans =max(ans, temp.step +1);
fresh--;
que.push((node){x, y, temp.step +1});}}}
1662 对所有目标点距离最大
n = grid.size(), m = grid[0].size();for(int i =0; i < n;++i){for(int j =0; j < m;++j){if(grid[i][j]==1){
que.push((node){i, j});}}}if(que.size()== n * m || que.size()==0)return-1;
node temp;// 通过队列所有 1 出来访问肯定是一层层靠近最终目标while(!que.empty()){
temp = que.front();
que.pop();for(int i =0; i <4;++i){int x = temp.x + dir[i][0];int y = temp.y + dir[i][1];if(x <0|| y <0|| x == n || y == m || grid[x][y]!=0)continue;// 通过修改 grid 控制访问过
grid[x][y]= grid[temp.x][temp.y]+1;// 结构体无需添加 step
que.push((node){x, y});}}return grid[temp.x][temp.y]-1;
417 给定条件到边界
// 逆向思考,看从边界出发,有哪些点可以到达边界// 先讲上左两侧陆地推入队列// check 标记访问情况for(int i =0; i < m; i++){
que.push((node){0, i});
check[0][i]=1;}for(int i =1; i < n;++i){
que.push((node){i,0});
check[i][0]=1;}// 第一次队列标记 check 改为 1...for(int i =0; i < n;++i){
que.push((node){i, m -1});
check[i][m -1]+=2;}for(int i =0; i < m -1;++i){
que.push((node){n -1, i});
check[n -1][i]+=2;}// 第二次队列标记 check += 2 check == 3 说明都可以到达,退出
529 扫雷
// 返回周围雷数intfunc(int x,int y, vector<vector<char>>& mmap){int t =0;for(int i =0; i <8;++i){int xx = x + dir[i][0];int yy = y + dir[i][1];if(xx <0|| yy <0|| xx == n || yy == m){continue;}
t +=(mmap[xx][yy]=='M');}return t;}// 只有空白会出发批量点开if(func(click[0], click[1], board)==0){
board[click[0]][click[1]]='B';
que.push((node){click[0], click[1]});}else{
board[click[0]][click[1]]=func(click[0], click[1], board)+'0';return board;}...// 在 while 队列查找循环中同样是只点击空格的时候才继续推开int t =func(x, y, board);if(t !=0){
board[x][y]= t +'0';}else{
board[x][y]='B';
que.push((node){x, y});}
934 最短的桥,求最短距离
// 两个 for 先找出起点推入队列,然后标记(本体可改原地图来达到标记目的)if(A[i][j]==1){
A[i][j]=2;
que.push((node){i, j,0});func(i, j, A);break;}...// while 队列循环 再标记,若出现 A[x][y] == 1 到达目的返回
752 打开转盘锁所需最少步数
// 记录转盘状态struct node {
string status;int step;};...// 对于转盘状态,广搜for(int i =0; i <4;++i){
string t = temp.status;
t[i]++;if(t[i]>'9'){
t[i]='0';}if(t == target){return temp.step +1;}if(m[t]==0){
m[t]=1;
que.push((node){t, temp.step +1});}
t = temp.status;
t[i]--;if(t[i]<'0'){
t[i]='9';}if(t == target){return temp.step +1;}if(m[t]==0){
m[t]=1;
que.push((node){t, temp.step +1});}}
864 获取钥匙的最短路径
struct node {int x, y, status, step;};// 关键 check 记录状态还要状态点的拿钥匙的状态记录int n, m, check[35][35][200], key_cnt =0, end_status;// a-f 钥匙用位标记判开 end_status 根据 key_cnt 钥匙数量 为其中一位数int bit2[10]={1,2,4,8,16,32,64,128};// ... 注意起点可走if(mmap[i][j]=='@'){
que.push((node){i, j,0,0});
check[i][j][0]=1;
mmap[i][j]='.';}if(mmap[i][j]>='a'&& mmap[i][j]<='f'){
key_cnt++;}
end_stats = bit2[key_cnt]-1;...if(temp.status == end_status){return temp.step;}...// 循环内根据状态推入if(x <0|| y <0|| x == n || y == m || check[x][y][temp.status]==1){continue;}
check[x][y][temp.status]=1;if(mmap[x][y]=='.'){
que.push((node){x, y, temp.status, temp.step +1});}elseif(mmap[x][y]>='a'&& mmap[x][y]<='f'){// 该点位钥匙开启
check[x][y][temp.status | bit2[mmap[x][y]-'a']]=1;
que.push((node){x, y, temp.status | bit2[mmap[x][y]-'a'], temp.step +1});}elseif(mmap[x][y]>='A'&& mmap[x][y]<='F'&&(temp.status & bit2[mmap[x][y]-'A'])){
que.push((node){x, y, temp.status, temp.step +1});}
顺序表和链表
19 删除倒数第 n 个节点
// 用两个标记,第一个标记先跑到第 n 个节点// 然后两个标记同时往后,直到第一个标记到达末尾// 删除第二个标记