leetcode 题解记录

千题只是目前的一个目标,希望能磨炼基本功并一直保持熟练,原创代码更新在github,在这里会进行简单总结:

---------------------------------------------------------------------------------------------------------------------------------

代码维护

GitHub - huqinwei/leetcode_practice: C++

文件说明:

vs2015工程

100题一个文件

Solution_1xx.h代表100-199题

Solution_11xx.h代表1100-1199题

TODO:考虑做一个检索,甚至只需要输入题号就能执行函数(但是有些函数甚至需要依赖leetcode提供接口去验证某些数字,所以再考虑)

---------------------------------------------------------------------------------------------------------------------------------

经验与思路整理:

时间复杂度:

其实刷题提速的关键就是明确哪些过程是必须要走的,哪些过程是可以省略的,并且有办法把它省略。

学习优先级大于造轮子:

刷题覆盖类型还不全面,就去参加了双周赛,结果大费周章设计各种容器各种参数,甚至优化容器的检索速度,最后发现速度瓶颈不在于此,方法也有比这代码更少更快的。所以强行做题还是偶尔,优先学一些现成思路和方案,效率会更高。

---------------------------------------------------------------------------------------------------------------------------------

题目索引:

1.

2.

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

看到大多数人是用的sort,并且还在炫耀打败了python下9x%的人,感觉不太对,这题最好的预期给的是O(log(m+n)),即使笨一点,双指针,复杂度也就只有O(m+n)啊(取个巧,到一半就结束O((m+n)/2),而且我也不用真的插入那个容器内),但是把两个数组放一起sort,额。。。

随便几百个数据:

sort方法:cost time: 0.000389

双指针法:cost time: 1.3e-05

leetcode 48 . 旋转图像

其实很简单,但是有一次被问到,状态不好翻车了,首先排除cosx+siny的坐标轴转换法,下标没有负的,不好处理,很繁琐,还要处理一次小数,虽然90度的cos和sin还好。

试图直接用new_i=j,new_j=w-i-1之类的直接不对。

其实就是一个对flip操作的烂熟过程就搞定了,和翻转字符串类似,翻转矩阵即可。

翻转矩阵也有坑,左右flip和上下flip达不到“90度”的要求,试想手拿A4纸,左右flip,上下flip,长高颠倒了吗?!

想顺时针90度旋转矩阵,可以对角线翻折一下,再上下(左右)翻转一下,对角线翻转还有很多下标细节要推,总之是一个吃熟练度的题,或者至少要熟练思路。

.......

leetcode 213.打家劫舍2(解析见下方)

leetcode 567  字符串的排列 字母统计表对比+动态低复杂度更新

leetcode 707 设计链表:单链表即可,繁琐活,一致性,如果维护一个tail,速度会进一步提升。

leetcode 733 图像渲染:我从一开始就设计的完备逻辑,所以一次过了,后来试了取巧提速,失败了,简单说,数据集的一个因素要考虑进来,就是,oldColor==newColor,如此,你需要自己去维护visited,然后再单独去写一个结果。

.....

999.

5836(1976)到达目的地的方案数:

自己设计数据结构和冗长的参数列表,颇费了一番心思,最后超时了,改进后也只能卡在数据集29,DFS加动态设定最短路径阈值的方式还是不够快,我想到了一些BFS+DP的思路,但是还没实践,

这题我的核心思路是:利用dp给每个点设立淘汰机制,到达这个点的value取min,其余的过程都可以排除了,因为更远,题目只求最近的,如果利用这个性质,就考虑BFS更好了,另外就是当一条路径已经走过了某一点dp[i],到达了dp[i+1],这时候别的路线突然更新了dp[i],让它也无效了,是否有办法有必要把它也中断(与此同时,是否能拿到题目要求的信息)。

看题解是dijkstra+dp,说明做题还不够多,光费脑筋也不行,还是要先学会现有方法。

类型索引:

双指针:

可以变相当计数器用,例如19. 删除链表的倒数第 N 个结点

链表:

设计链表:单链表即可,繁琐活,一致性,如果维护一个tail,速度会进一步提升。

DFS&BFS:

我典型的DFS就是岛屿数量,需要注意逻辑的完备性,是否需要保持原始信息不动。

动态规划:

其实入门不难,就三点:知道状态是怎么迭代的,知道初始怎么设置,最重要的是,要知道到底要求的是什么东西

DP的误区:无脑堆迭代公式,忘了求的目标是什么,只有时刻明确目标,才能设计好题解。

爬楼梯:

滑窗法直接算,pqr的滑窗概念,相似的还能用到fibonacci和tribonacci。

dp数组法,和滑窗本质一样,就是形式不同。设好初始值,每一层的可能性就是前两层的可能性的叠加。

求的是可能性。

最小花费爬楼梯:你的“当前状态”其实应该是走过所有楼梯的下一个位置,n节楼梯的结束位置是[n](起始0)。

求的是花费。

爬楼梯递归为什么能成立?有时候我就反思,dp[i-1]已经包含了dp[i-2],为什么dp[i]还能是dp[i-1]+dp[i-2]?因为dp[i-1]只包含了dp[i-2]走一步的可能性,现在dp[i]是从dp[i-2]走两步,所以爬楼梯的迭代过程本质是,每一个dp[i-1]只储存了能确定走到这个台阶i-1的所有可能性,而dp[i]可能由两个位置“一步”走过来,所以dp[i]是求和前两步的可能性是没错的。

P(i)=p(i-1)p(i-1走一步)+p(i-2)p(i-2走二步)

=P(i-2)p(i-2走一步)p(i-1走一步)+p(i-2)p(i-2走二步)

打家劫舍:

其实可以看做最大花费爬楼梯。和爬楼梯不太一样的是,爬楼梯没有互斥条件,互斥条件是打家劫舍难的一点,其实想明白也就简单了,每条状态i都是衡量如下条件得出来的:

max(dp[i-2]+dp[i],dp[i-1])

打家劫舍2

这里边有两个提升过程,是分两步完成的。第一个是难度提升,需要思考一下DP的本质,DP的本质是状态存储,是牺牲细节信息的,无论你找dp[i-1]还是dp[i],他都包含了nums[0],nums[0]都已经作为输入信息累积到这个dp数组内了,是无论如何也不能从DP中分离出来的。这时候,无脑套公式是没用的,解题需要求助于dp之外的trick——分两次dp,一次彻底不带nums[0],也就是dp1范围[0,n-2],dp2范围[1,n-1](最后一个数字下标是n-1)

第二个是速度提升,规划完了两个dp,最后max一下,就完成了最优解,但是我发现排名不靠前,4ms,因为我两个dp分别走了两个循环,我的复杂度是O(2n),虽然两个循环的区间不一样,但是也就首尾分别差1,其余全是重复。这时候把两个循环合并为一个循环,只是需要稍微给两个dp加不同的上下限控制if语句,就能把C++的速度提升到0ms,这是一个基于时间复杂度思考的过程

已分享至github:int rob_II(vector<int>& nums);

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值