【算法】LeetCode上一些经典好题(update@0205)

LeetCode从15年末也就是大四的时候开始陆陆续续的刷了150多道题,今年因为马上要找工作了,所以又开始刷起来,觉得有必要记录一下做一些题目时的想法,和记录下一些好的题目和discuss里好的方法

1.巧妙利用排序的比较函数

179. Largest Number
这道题说给几个数,然后将这几个拼接在一起,使得拼接出来的数最大。
其实就是一个排序,但是一开始我写比较函数的时候想当然的以为按照第一个数字比大小,后来发现45,4这两个数字应该把45放前面,加上之后,又发现12,121,又应该把12放前面,这样的话讨论的情况就太多了。
看了discuss才发现一个精妙的解决办法,就是a,b两个数,比较函数直接返回 a+b<b+a的值。(a,b已转成string类型)直切问题根本,简直棒极了。
另外还发现了比较函数的简洁写法

sort(begin(arr), end(arr), [](string &s1, string &s2){ return s1+s2>s2+s1; });

可以直接写在sort函数里面,这个以前没用用过,写法非常黑科技。


2.矩阵旋转90°用到的tricky方法

48. Rotate Image
这道题是使用常数空间,将一个矩阵顺时针旋转90°。我一开始的想法是把正方向分成四个方块,但是这样的话需要讨论中线是否存在的情况,看discuss发现一个好的解决这个问题的办法,就是把正方形分成四个三角形(注意三角形左斜边可以取到,右斜边取不到)
另外还看到了另外一个奇技淫巧:先将正方形上下翻转,再对角翻转。


3.判断一个数是不是2的指数

231.Power of Two

1.一方面要考虑负数和0的输入情况
2.另一方面有个简便方法:(即一个数与其-1相&,则可以消去这个数最后一位的1);

bool isPowerOfTwo(int n) {        
     return n > 0 && !(n&(n-1));    
}

4.找出一个数组中是否有符合某种大小模式的三个数 题

456.132 Pattern
这道题是让找出是否有符合132这种模式的数

首先先看一道类似题,我们可以先看如何找是否符合123这种模式的数,即s1 < s2< s3这种的,即下面这道题。
334. Increasing Triplet Subsequence
其实s1 < s2< s3这种模式本质上就是最长上升子序列的变种,这次只用找3个就好了。而最长上升子序列需要维护一个数组a[n],其中a[i]代表长度为i的最长上升子序列,末尾最小值。

所以这道题,要找 s1 < s3 < s2 的数,可以先从s2扫描,从右往左扫,一次把当前的值加到优先队列里,并把所有小于当前值得都给弹出来,优先队列里存的是s2所有可能的候选,弹出来的元素是s3的候选,s3一直选弹出元素最大的即可,最后一直到第一个出现比s3小的数,说明找到了s1
其实以上的实现可以用一个栈来实现。


5.三道比较相似的划分题目

416. Partition Equal Subset Sum
给一个数组,将其分成两部分,使其两部分的和尽可能的接近。
MD忘了那个题目是啥了。。。。。。
给一个数组,将其分成元素个数相等的两部分,使其两部分的和尽可能的接近。
410. Split Array Largest Sum
给一个数组,将其分成n部分,使其每部分的和尽可能的接近(题目中给出的条件是,使其中和最大的一组数,和最小)。

第一个问题,典型的01背包问题,即搜索背包能否装下SUM/2的大小
第二个问题,隐藏的比较深一点,其实也是一个背包问题,只不过是二维费用问题,即隐藏了一个背包放置数量为n/2个

dp[i][count][sum] = max{ dp[i-1][count-1][sum-a[i]] , dp[i-1][count][sum] }; 

仿一维背包问题,将其优化成一个二维数组

第三个问题比较难的,


6.动态规划的思考

动态规划,个人觉得就是跟备忘录(即记录中间过程的递归算法)很接近的,只不过其是自底向上的而已。一般如果题目一时没有思路可以考虑用递归,然后递归有几个参数,动态规划的dp数组就有几维。大部分情况下需要限制次数的,则次数也代表一个维度。
如果一个动规数组不能满足要求的话,可以考虑用两个动规数组。(对应于多个递归函数的嵌套)
典型的例子是:
309. Best Time to Buy and Sell Stock with Cooldown
188. Best Time to Buy and Sell Stock IV
股票买卖的题,可以重新生成一个数组diff[i-1] = prices[i]-prices[i-1],看成选出其中最大元素和的问题。
309这道题是,每次买卖之后第二天也不能买卖,所以等价于在diff[]数组中找出最大的子段和,而且每个字段之间间隔至少为2个元素。
则用动规思路 dp[i] = max(当前元素不选时:dp[i-1],当前元素选时dp[i-3]) 但此时有个问题,就是dp表示到目前为止的时候,最大的子段和,那么其实并不能确定dp[i-3]就是满足题意的,所以需要一个两个数组,dp1,dp2分别表示到目前为止最大的字段和,和,到目前为止,且选上最后一个元素的时候的最大字段和
则:

dp2[i] = max(dp2[i-1],dp2[i-3])+diff[i];
dp1[i] = max(dp1[i-1],dp2[i]);

188这道题就是限制了交易次数的交易最大利润,即为在一个数组中,求不超过m个字段,使其和最大。思考dp数组,k为交易次数,i为第i个元素
dp[k][i] = max(当前元素不选时dp[k][i-1],当前元素选时…)
就会发现当前元素选时,还是无法区分是否跟前面连着,所以可以考虑用两个数组
dp1,dp2分别表示到目前为止不超过k个最大的字段和,和,到目前为止不超过k个字段,且选上最后一个元素的时候的最大字段和

dp2[k][i] = max(dp2[k][i-1],dp1[k-1][i-1])+diff[i];
dp1[k][i] = max(dp1[k][i-1],dp2[k][i]);

注意到第一个等式上面的tricky的地方,即dp2[k][i-1]选择的话,如果再选择当前的,不增加k值的,所以这个地方是dp2[k][i-1],同理dp1也是。


7.迭代器

  1. Flatten Nested List Iterator
    这道题风格非常的不一样,就是迭代器的实现过程。之前我一直没怎么用过C++中类的循环定义,即类里面再有这个类本身的声明和应用;还有迭代器的定义问题。
    看一下标准代码吧:
class NestedIterator {
public:
    NestedIterator(vector<NestedInteger> &nestedList) {
        begins.push(nestedList.begin());
        ends.push(nestedList.end());
    }
    int next() {
        hasNext();
        return (begins.top()++)->getInteger();
    }
    bool hasNext() {
        while
  • 3
    点赞
  • 36
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值