Hot100

115给定一个字符串 s 和一个字符串 t ,计算在 s 的子序列中 t 出现的个数。
s = "rabbbit", t = "rabbit"
思路:dp[i][j]表示s[0~i] 与 t[0~j]有几种匹配结果
dp[i][j] = dp[i-1][j] //无论什么时候都可以将第i位删掉,去查看s[0/i-1]与t[0/j]的匹配
此外当第i位与第j位匹配的时候,还可以加入s[0/i-1] 和 t[0/j-1]的匹配情况
因此 dp[i][j] = dp[i-1][j] + (dp[i-1][j-1] if s[i] == t[j])

给定n位,每一位可以选0-9,总共的选法。一共肯定是有10^n种1、可以循环n次
for(int i = 0; I < 9; ++i) 
    for(int j = 0; j <= 9; ++j)
        for(int k = 0; k<= 9; ++k)
2、可以使用递归
int n; //数的位数

string str = "000";
void dfs(int start) {
    if(start == n) {
        cout << str << endl;
        return;
    }
    for(int i = 0; i <= 9; ++i) {
        str[start] = char(i);
        dfs(start+1);
    }
}

15三数之和先排序,固定一个数可以转换为两数之和,使用双指针。注意去重i,j,k的重复
10正则表示式匹配到着看,*只能是将前一个数重复0 1 ……次。看手画图解
92

反转链表

反转从位置 m 到 n 的链表。请使用一趟扫描完成反转。

说明:
1 ≤ m ≤ n ≤ 链表长度。

1、新建节点的方式,从pre开始遍历到last,每次都在last后面新建节点,最后把pre到last删除就好

2、修改next值,记录pre的下一个prenext,每次将prenext指向pre,更新pre 和prenext的值

注意判断m=1的情况,也就是把原来的头节点删了

31

下一个排列

算法需要将给定数字序列重新排列成字典序中下一个更大的排列。

思路:下一个大的排列,肯定是将某个大的数换到了前面,因此要找下一个最大的,就找最后一个升序的对儿,123476,比方找到了最后的是4-7和4-6,最后一个对是4-6,因此将4-6交换得到674,将74正序排序,就得到最终结果
32

最长有效括号

给你一个只包含 '(' 和 ')' 的字符串,找出最长有效(格式正确且连续)括号子串的长度。

")()())" 结果是4

思路:将括号压栈,左右括号匹配时就弹栈,最后栈里剩下的序列,间隔最大的差就是最长的括号长度

比如左边题最后栈里剩 0 5,因此05之间的括号都是匹配的,所以最长的就是5-0-1 = 4

注意:

1、当栈为空或当前时'('就压栈。2、当前是右括号就与栈顶匹配,如果匹配到左括号就弹栈,3、否则就把右括号压栈

第3步一定要注意!!!

153

没有重复元素

假设按照升序排序的数组在预先未知的某个点上进行了旋转。请找出其中最小的元素。

二分做,基于一个定论

mid跟right比,如果nums[mid] > nums[right],那么转折点一定在mid右边,所以left = mid + 1

如果nums[mid] < nums[right] 那么从mid到right一定是升序的!但mid也可能是转折点,因此left = mid

154

有重复元素

假设按照升序排序的数组在预先未知的某个点上进行了旋转。请找出其中最小的元素。

基于上面的定论,因为此时如果nums[mid] == nums[right],我们分不清是在左边还在右边,但无论是哪边,nums[right]在数组中有个相同的数nums[mid],因此就把nums[right]删掉,缩小边界

因此由二分变成三分

76

最小覆盖子串

给你一个字符串 s 、一个字符串 t 。返回 s 中涵盖 t 所有字符的最小子串。

/*

1、见到子串要想到滑动窗口

2、滑动窗口永远设置都是right的还没往进加的,所以进入循环后第一步就是将s[right++]加到窗口中

3、计算窗口长度时,要记住此时right是已经递增过1的,所以窗口长=right-left

*/

使用滑动窗口,使用两个map记录窗口和子串中的字符个数。只要当前的滑动窗口中包含了子串t中的所有字符,那么就是一个有效值,只是需要收缩左侧来得到最小字符串

121买卖股票的最佳时期

看labuladong的题解,注意如果表示-1天的话,dp[-1][k][0] = 0. dp[-1][k][1] = INT_MIN

如果表示第0天的话,dp[0][k][0] = 0, dp[0][k][1] = -prices[0]

82

删除链表中的重复元素

给定一个排序链表,删除所有含有重复数字的节点,只保留原始链表中 没有重复出现 的数字

输入: 1->2->3->3->4->4->5
输出: 1->2->5

我的思路与其类似,也是先找一个cur,之后比较cur.next 和 cur.next.next

 * 不同的是,我每次删除的是cur.next.next,让cur.next.next指向新的节点

 * 而本思路是如果cur.next == cur.next.next,记录cur.next.val的值

 * 每次去改变cur.next,如果等于x就让cur.next指向下一个

 * 思路比我的要简单

341

扁平化嵌套列表

列表中的每一项或者为一个整数,或者是另一个列表。其中列表的元素也可能是整数或是其他列表。

1、递归,在类构造时就使用递归将列表扁平

2、循环+栈,在每次判断hasNext时将列表扁平(将列表从后向前压入栈,就能使得打印栈顶时是由前到后的)

198打家劫舍问题汇总打家劫舍问题汇总

56,1288

986

区间覆盖,删除,交集等操作一般都是先按左边界排序,之后看区间左右的端点的关系,看lubuladong的文章
460

LFU缓存设计

淘汰最近最少使用

设置三个hash

unordered_map keyToFreq;

unordered_map keyToNode;

unordered_map freqToKeys;

142寻找环形链表的入口先找到相遇的点,之后一个点从head开始,一个点从相遇点开始,相等的点就是入口点
1109

航班预定统计

前缀数组和差分数组

前缀数组适合数组元素不变,但是要多次计算数组某一区间和的情况

差分数组适合数组某一区间元素不断改变,最后求数组中的值到底是多少

207课程表设计拓扑排序解法
最小生成树

kruskal算法和prim算法

这算法是将图中所有顶点连接起来的最短边和,n个顶点,n-1条边

最短路径

Dijkstra算法和Floyd算法

这是找图中某一点到其他点的最短路径,最短路径并不意味着是最小生成树。

847旅行商问题再看看
72编辑距离(对一个字符串 增删改 变为另一个字符串)

这题用dp,dp[i][j]表示,word1的0-i转为word20-j的步数,

dp[i-1][j-1]表示修改,dp[i-1][j]表示对word2增加一位(即是对word1减去最后1位),dp[i][j-1]表示对word1增加一位

此题和127单词接龙不一样,单词接龙是指将一个word按照word list的规则转为word2,这题用图的BFS做

75颜色分类,荷兰国旗问题

此题可以抽象为,给定一个值K,要求把数组中小于K的元素放到数组的左边,大于K的元素放到数组的右边

看起来很像qsort的每一步,但是qsort只是每次把首位的数放到正确的位置pos,也就是保证pos之前的数都小于首位,pos之后的数都大于首位,但是并不保证pos之前 之后的数是不是顺序的,0 1 0 2 3 2 3,此时的pos在3,确实保证了上述条件,但两侧都是无序的。

而荷兰国旗问题,比qsort的每一步要更进一点,它会保证K元素在中心,小于K的在左边,大于K的在右边,但是不保证小于 或者 大于的数是有序的。

470用rand7生成rand10

用randa生成randb

if(a > b) 比方说rand10生成rand7,只要产生的数大于7就重新产生

if(a < b) 可以用7*(rand()-1) + rand7()生成1-49的随机数,再生成rand10

用randa,randb生成randab随机数,比方用rand7,rand10生成rand70的

方法1、7*(rand10() - 1) + rand7()

方法2、10*(rand7() - 1) + rand10()

81

搜索旋转排序数组II

在旋转的排序数组中搜索target,而不是找旋转点

思路:

1、先确定mid的位置,mid跟nums[j]比较,确定mid在前半段还是后半段

2、确定target的位置,a) mid在前面,target  < nums[mid]有两种情况,target在mid前面和target在后半段

                                    b) mid在后面,target > nums[mid]也有两种情况,target在mid后面和target在前半段

                                     通过比较target和nums[j[的值确定target的位置

最大公约数,最小公倍数

最大公约数:

1、辗转相除法,a是两数种较大,b是两数中较小,a与b的最大公约数 =  (a %b)与 b的最大公约数

2、更相减损术,a是两数种较大,b是两数中较小,a与b的最大公约数 =  (a - b)与 b的最大公约数

3、可以判断两数的奇偶,选择位选算来加速

链接

最小公倍数:

a与b 的乘积 = a与b的最大公约数 * a与b的最大公倍数

ab最小公倍数 = a*b / c (c是ab的最共公约数)

28字符串匹配

KMP算法

讲解

368最大整除子集

类似于最大递增子序列

每次到一个i的时候,都去和i前面的所有j去比较

不同的是,递增子序列比较的是大小,这个题比较的是能否整除

具体看题解

4寻找两个正序数组的中位数

简单的方法就是转为找第k = len/2大个元素,在两个数组中建立两个指针,(如果一个数组为空,或者该数组当前值大于另一个数组的当前值,那么就在另一个数组中找),因为可能是偶数要找两个值嘛,所以用left和right记录,每次移动的时候先用left来记录right,再将right移动。如果len是奇数,那么直接返回right,如果是偶数,那么就返回(left+right) / 2.0,见提交记录

复杂的方法是进行两个数组中进行一半一半的比较,将时间复杂度降为O(log(m+n)),见提交记录

743图的最短路径问题

1、迪杰斯特拉算法:算法的关键是使用一个最小堆,每次从最小堆中取出最小的

2、Floyd算法:记住一定要先初始化矩阵!!

46combination和permutation

permutation的时间复杂度是O(n*n!),其中n!是递归树的n!个叶子节点,n是每次将一种可行解放入ans的时间

combination的时间复杂度是O(n*2^n) 其中2^n是每个数可选可不选的情况,n是每次将一种可行解放入ans的时间,这是最坏的时间

1838最高频数       看题解,将k作为滑动窗口的阈值,频数是滑动窗口的长度,每次右移窗口时,窗口中的总操作total会改变,与k进行比较。 看官方题解。
227        基本计算器

对于式子1+2*3+4

思路就是遇到+ -时,直接将数字压入栈,遇到* /时,将数字与栈顶元素进行运算

主要有很多细节需要注意:

1、只有数字的情况

2、最后一个数字的情况

将式子转为 +1+2*3+4

对于每一个数字,前面的那个符号就是其自己的符号

662二叉树的最大宽度(空节点也算宽 )对每个节点进行编号,左孩子=index*2 +1, 右孩子=index*2 + 2.每一层的宽度就是队列中最左侧节点与最右侧节点的差
384       随机打乱数组

1、交换法

2、每次产生随机数的时候只产生i~back的随机数 rand()%(size - i) + i

对于nums = {1, 2, 3, 4, 5}

对于第0位,任意的rand()%5放在第一位都可以满足1/5,比方是3,那么1和3进行交换 {3, 2, 1, 4, 5}

对于第1位,rand()%4 + 1,选取{2, 1, 4, 5},概率是 4/5 * 1/4 = 1/5, 4/5是指不能选3,只能在2145中选 自然就是4/5

对于第2位,3/5 * 1/3 = 1/5

705设计哈希集合

使用vector<list<int>> 来模拟拉链法哈希表

hash表长度选择,即尽量选择素数,这样可以最大程度上避免冲突

也有hash表长度len选择为2的幂,这是因为key%len = key & (len - 1),主要是考虑了位运算的操作比较快

同时注意对vector中list操作时,注意迭代器失效的问题

29       不使用/, *, %来计算两个数的除法

思想:不断减去 减数求得商,可以使用翻倍来加速

60/8 = (60 - 32 - 16)/8 + 4 + 2 = 1 + 4 + 2 = 7

560

和为K的子数组

这个数组不是有序的,特别容易想成滑动窗口,因为滑动窗口默认i++是变小,j++是变大。但这题中的数组不是有序的。因此用前缀和+map。pre[i]是0-i个数的和,所以说在map中如果存在pre[i]-k,那么就一定存在一个j,0-j的值是pre[i]-k。所以i-j的值就是k  pre[i] - (pre[i] - k) = k

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值