LeetCode刷题复习

内容参考CyC大佬的LeetCode复习指南

算法思想复习

在考虑更优解时,先从数据状况入手,一般C++1s可以运行 1 0 7 − 1 0 8 10^7 - 10^8 107108次,看有何特点可以利用,如有序,回文,重复,推公式等

1.1双指针、快慢指针

  • 双指针求和,先使数组有序,然后根据大小判断哪个指针移动。
  • 叠加时需要考虑是否爆int甚至是大数运算。
  • 633需要考虑从0开始,两个数相等也可,爆int。
  • 字母注意大小写的考虑。
  • 指针在数组或容器中移动,需要考虑,所指是否溢出。
  • 680
  • 88 需要在原数组操作,为避免覆盖可以从后往前。
  • 141 链表迭代首要判断所指是否为空。

1.2排序

  • partition用于求解第k元素问题,215使用partition。
  • 堆用于求解k个最小的问题也可以用于求解第k个元素问题。
  • 桶排序347
  • 75 不能用h - -,会使l提前跟h撞

1.3贪心

  • 435 区间贪心
  • 406 先插入最大的身高,使其有序,之后插入的位置对其就没有影响
  • 对于边界不好处理的问题可以自己加个边界 605
  • 53 连续是关键
  • 763

1.4二分查找

适用于有序查找。求重复元素最左或最右时推出判断为 l < h。

  • 744
  • upper_bound( begin,end,num):从数组的begin位置到end-1位置二分查找第一个大于num的数字,找到返回该数字的地址,不存在则返回end。通过返回的地址减去起始地址begin,得到找到数字在数组中的下标。
    lower_bound( begin,end,num):从数组的begin位置到end-1位置二分查找第一个大于或等于num的数字,找到返回该数字的地址,不存在则返回end。通过返回的地址减去起始地址begin,得到找到数字在数组中的下标。
    lower_bound( begin,end,num,greater< type> () ):从数组的begin位置到end-1位置二分查找第一个小于或等于num的数字,找到返回该数字的地址,不存在则返回end。通过返回的地址减去起始地址begin,得到找到数字在数组中的下标。
  • 540 153
  • 对于右边界赋值不变的情况,不能取 <= 会死循环,如 h = m。
  • 34 二分变种,第二个h为size,因为可能指向最后一个。
int lower_bound(int A[], int l, int r, int x) {
	while (l < r) {
		int m = l + (r - l) / 2;
		if (A[m] >= x)
			r = m;
		else
			l = m + 1;
	}
	return l;
}

int upper_bound(int A[], int l, int r, int x) {
	while (l < r) {
		int m = l + (r - l) / 2;
		if (A[m] > x)
			r = m;
		else
			l = m + 1;
	}
	return l;
}
模板:
while (l < r) {
	int m = l + (r - l) / 2;
	if (true)
		r = m;
	else
		l = m + 1;
}
return l;
也可用于左闭右开情况

1.5递归

  • 241 要处理最后的单数字
  • 95

1.6搜索

1.6.1BFS

  • 279 127

1.6.2DFS

  • 695 dfs后记得改变状态,bfs也可。
  • 注意547无向图遍历的走向,也可用并查集
  • 染色、填充 130 417
    dfs + 回溯、剪枝:
  • 93 前导0, 小于 等于255, 组数不够情况
  • 79 把board也当做标记,可以更快
  • 257 temp不加 & 可以不回溯,回溯适用于所标记变量是全局使用的
  • 含有重复元素的搜索 ,47, 先排序,然后搜索时判断是否相等,并且之前的元素已被使用
  • 77 剪枝所剩循环不足以使k == 0, 40 判断重复时i > index.216 剪枝
  • 131每次循环是以取string字符个数,更优解是从后往前分解。
  • 37 dfs要有返回 51,行迭代,所以只需判断不在同列

1.7动态规划

1.7.1 斐波那契数列

1.7.2 矩阵的最小路径和

  • 经典题 64, 空间优化 O(1)操作
  • 62组合求解方式,总共需要走 m + n - 2步,这其中有 m - 1步是往下走
class Solution {
public:
    int uniquePaths(int m, int n) {
        int m1 = m + n - 2;
        int n1 = m - 1;
        long long re = 1;
        for (int i = 1; i <= n1; i++)
            re = re * (m1 - n1 + i) / i;
        return (int)re;
    }
};

1.7.3数组区间

  • 413

1.7.4分割整数

  • 343 对于第i个数最大可能为第j个数最大× (i - j)或者 j × (i - j)有动态方程 : d p [ i ] = m a x ( d p [ i ] , m a x ( j ∗ d p [ i − j ] , j ∗ ( i − j ) ) ) dp[i] = max(dp[i], max(j * dp[i - j], j * (i - j))) dp[i]=max(dp[i],max(jdp[ij],j(ij)))
  • 91

1.7.5最长递增子序列

  • 300注意初始化应为1, nlog(n)解法
  • 646用贪心要排序第二个元素,因为第二个元素决定了,还剩多少空间可以贪心。始终记住贪心策略是使目前最优而不影响后续最优情况。
    int findLongestChain(vector<vector<int>>& pairs) {
        int ssize = pairs.size();
        
        if  (ssize < 1)
            return 0;
        sort(pairs.begin(), pairs.end(), [] (const vector<int> &a, const vector<int> &b) {
            return a[1] < b[1];
        });
        
        int re = 1;
        int end = pairs[0][1];
        for (int i = 1; i < ssize; i++) {
            if (end < pairs[i][0]) {
                re++;
                end = pairs[i][1];
            }
        }
        return re;
    }

1.7.6 0-1背包

参考背包九讲

  • 416注意sum不能被整除的特判
  • 494公式推导
  • 474分组背包
  • 322完全背包,内侧循环为正序
  • 518完全背包求方案数,注意初始化,状态变量定义为bool
  • 377顺序完全背包

1.7.7 股票交易

  • 309状态转移
  • 714注意初始状态的赋值
  • 123设为INT_MIN迭代从 0开始
  • 188对于k与size大小比较的讨论,我好菜。

1.7.8 字符串编辑

  • 583拿总长度减去最长公共序列
  • 72
  • dp[i - 1][j - 1]代表删除, dp[i - 1][j - 1] + 1代表该变值, dp[i - 1][j]代表插入,初始状态。
  • 650越小越好

1.8数学相关

  • 素数
bool isPrime(int n) {
	if (n <= 1) return false;
	for (int i = 2; i * i <= n; i++) {
		if (n % i == 0)
		return false;
	}
	return true;
}
  • 最大公约数(gcd)
int gcd (int a,int b) {
	return b == 0 ? a : gcb(b , a % b);
}
 

位操作实现:

int gcd(int a, int b) {
	if (a <  b)
	return gcd(b, a)l
	if (b == 0)
	return a;
	if ((a & 1) == 0 && (b & 1) == 0)) {
		retrun 2 * gcd(a >> 1, b >> 1);
	} else if ((a & 1) == 1 && (b & 1) == 0) {
		return gcd(a >> 1, b);
	} else if((a & 1) == 0 && (b & 1) == 1) {
		return gcd(a, b >> 1);
	} else {
		return gcd(b, a - b);
	}
]
  • 最小公倍数(lcm),即除去最大公约数
  • 进制转换,504用递归写正好不需要reverse。405
  • 阶乘
  • 大数加减

1.8.2 位运算

  • 260 n&(-n) 得到 n 的位级表示中最低的那一位。-n 得到 n 的反码加 1,对于二进制表示 10110100,-n 得到 01001100,相与得到 00000100
交换两个整数
a = a ^ b;
b = a ^ b;
a = a ^ b;
  • n & (n - 1)操作,可以去除最低位的1
  • 342 476 371 318

2数据结构

2.1链表

  • 一定要注意判空
  • 注意节点的更新,比如cnt,pre等
  • 19 移动到nullptr情况
  • 24
  • 一般需要加个头,方便处理

2.2树

2.2.1递归

  • 110从下往上的方法

  • 617 437 111 404 687

  • 337使用dfs时需要对比哪个方式最大并不是路线已固定

  • 非递归中序遍历,先用cur存当前节点,一直遍历left到底,push,弹出最左,打印,然后push该节点right,循环。

2.2.2BST

2.2.3 Trie

  • 677

2.3栈和队列

  • 栈的经典作用,括号匹配,匹配更新
  • 栈实现队,队实现栈,数组实现栈队
栈实现队列:队列要求先进先出,在第一个栈反转后,再用第二栈反转即可
class MyQueue {
public:
    stack<int> s1,s2;
    MyQueue() {

    }
    
    void push(int x) {
        s1.push(x);
        
    }
    
    int pop() {
        if (s2.empty()){
            while (!s1.empty()) {
            int temp = s1.top();
            s1.pop();
            s2.push(temp);
            }
        }
        int re = s2.top();
        s2.pop();
        return re;
    }
    int peek() {
        if (s2.empty()){
            while (!s1.empty()) {
            int temp = s1.top();
            s1.pop();
            s2.push(temp);
            }
        }
        int re = s2.top();
        return re;
    }
    bool empty() {
        if (s1.empty() && s2.empty())
            return true;
        return false;
    }
};
用队实现栈:栈要求后进先出,所以使用两个队列,当有push时,把q1所有元素放到q2,
再push元素,最后在q2元素放入q1即可实现栈序
class MyStack {
public:
    /** Initialize your data structure here. */
    queue<int> q1,q2;
    MyStack() {
        
    }
    void push(int x) {
        if(q1.empty()) {
            q1.push(x);
        } else {
            while (!q1.empty()) {
                int temp = q1.front();
                q1.pop();
                q2.push(temp);
            }
            q1.push(x);
            while (!q2.empty()) {
                int temp = q2.front();
                q2.pop();
                q1.push(temp);
            }
        }
    }
    int pop() {
        int temp = q1.front();
        q1.pop();
        return temp;
    }
    
    int top() {
        return q1.front();
    }
    
    bool empty() {
        return q1.empty();
    }
};
数组实现队:用head和tail来记录相应位置
int q[100], head = 0, tail = 0;
void push(int x) {
	q[++tail] = x;
}
int pop() {
	return q[++head];
}
bool empty() {
	return head >= tail;
}
数组实现栈:
int s[100], head = 0;
void push(int x) {
	s[++head] = x;
}
int top() {
	return s[head - 1];
}
void pop() {
	head--;
}
bool empty() {
	return head == 0;
}
  • 单调队列、单调栈 lc239

//单调队列:
// 假设解决滑动窗口问题

int a[200000];
struct node
{ 
    int x,p;
    node(){}
    node(int xx,int pp){x=xx;p=pp;}
}list[200000];

int main()
{
 
    int n,m;
    scanf("%d%d",&n,&m);
    for(int i = 1;i <= n; i++) scanf("%d", &a[i]);
    int head = 1, tail = 1;
    list[1] = node(a[1], 1);
    for(int i = 2;i <= n; i++)
    {
 
        while(head <= tail && list[tail].x <= a[i]) tail--;//删尾,目前数比对队尾大
        list[++tail] = node(a[i], i);//得到最优解并插入
        while(i - list[head].p >= m) head++;//去头
        if(i >= m) printf("%d\n", list[head]);
    }
    return 0;
  • 739其实是一个从后往前的单调栈,在前面并且大的值我们就没必要把,日期靠后并且比他小的值存储。 503

2.4Hash

特点:空间O(N),查找O(1).

  • 128
class Solution {
public:
    int longestConsecutive(vector<int>& num) {
        if(num.size()==0)return 0;
        unordered_set<int> record(num.begin(),num.end());
        int res = 1;
        for(int n : num){
            if(record.find(n)==record.end()) continue;
            record.erase(n);
            int prev = n-1,next = n+1;
            while(record.find(prev)!=record.end()) record.erase(prev--);
            while(record.find(next)!=record.end()) record.erase(next++);
            res = max(res,next-prev-1);
        }
        return res;
    }
};

2.5字符串

  • 205 647 696
  • 双指针做substr巨好用。

2.6数组

  • 283 378二分是第一个大于等于
  • 交换元素 ,确定这个数所指的位置是否是该数。
		 while (nums[nums[i] - 1] != nums[i])
               swap(nums[i], nums[nums[i] - 1]);
  • 287双指针解法
  • 667
  • 对于标记操作,可以在数组自身进行
  • 769

2.7 图

  • 785二分图 定理:无向图G为二分图的一个充要条件是 1、G中至少包含两个顶点 2、G中所有的回路长度都必须是偶数.记得加一层循环处理非连通。
  • 拓扑排序
  • 并查集

2.8滑动窗口(Sliding Window)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值