Leetcode解题思路总结(Easy)

近来走上了Leetcode刷题之路,不过刷题背后更重要的是思路,掌握了方法,举一反三融会贯通。故在此我总结每道题的解题思路,这篇博客只涵盖Easy模式的题目,并按照题目从简单到难的顺序来列举。Medium和Hard模式的请见我另外2篇博客。


344 Reverse String,最近新加的一道题,用C++秒过,12秒,反转字符串,思路很简单,一种暴力方法就用直接用一个新的字符串存储,然后一个一个从后往前遍历旧的字符串。第二种就是原地用2个指针从两端往中间扫描,当left指针小于right指针时,就交换两个下标对应的值,否则就跳出循环。两种方法都是12ms过。同学用java做的时候遇到了坑,time limit exceed,好像是对于回车换行的情况,java的string支持的不行。只能先用toCharArray转换为用char数组,然后就好了。


292 Nim Game,传说中的一行代码搞定。属于很简单的博弈推理。

思路:假如只有1~3个石头,那我方肯定能赢,假若有4个石头,无论我取1~3个石头,对方总是能拿下最后一个石头,所以这时候我方必输。假若有5~7个石头,我能取对应的1~3个石头使得敌方处于只剩4个石头的状态(敌方必输)。假若有8个石头,则无论我取无论我取1~3个石头,对方总是能使得我处于只剩4个石头的状态(我方必输)。以此类推,不难得出,当石头数量为4的倍数时,我方必输。否则,我方必赢。


266 Palindrome Permutation ,题目如下:


思路:一开始可能会想着去生成所有的permutation,然后逐个枚举看有没有回文串。How Stupid!受到博客http://www.cnblogs.com/yrbbest/p/5021398.html的启发,

新思路如下:用一个集合set,逐个遍历这个字符串,如果便利到一个字母在set中没有的话,就加到set里,如果set里出现过这个字母,就把那个字母移出set。遍历结束时,如果set里的元素大于等于2的话,那就说明无法生成回文串。否则返回True。其实道理很简单,11122能形成回文串而111222则不能。这个思路其实跟括号匹配有点相似。其实set里剩下元素为0个的时候,回文串长度为偶数,set里剩下的元素只有1个的时候,回文串长度为奇数。


293 Flip Game

思路:http://blog.csdn.net/dolphin_wby/article/details/50336883


258 Add Digits

思路:一开始也会想着暴力模拟,但是显然有更好的方法,这道题应该属于数论,受到https://en.wikipedia.org/wiki/Digital_root的启发,我发现了一个如下的公式可以用来直接计算得到结果:


104 Maximum Depth of Binary Tree

思路:其实求二叉树的最大深度,就用递归,直接return 1 + max(DFS(left), DFS(right))就行,注意当节点为NULL的时候return 0


237 Delete Node in a Linked List

1 -> 2 -> 3 -> 4 变成1 -> 2 -> 4

思路:给定一个node,要删掉它,那我就把这个node的下一个node的value赋值给这个要删除的node,然后把这个node的next指针指向下一个node的下一个node就行了。


226 Invert Binary Tree

思路:递归&非递归版本


283 Move Zeroes

思路:双指针压缩法:实际上就是将所有的非0数向前尽可能的压缩,最后把没压缩的那部分全置0就行了。比如103040,先压缩成134,剩余的3为全置为0。过程中需要一个指针记录压缩到的位置。(参考:点击打开链接

空间复杂度为O(1),因为是就地解决的,时间复杂度为O(N)


100 Same Tree

思路:判断两棵树是否是等价的,有递归和非递归版本:点击打开链接

递归就是(1)若2棵树都是NULL,则返回true(2)若一棵树为空一棵树非空,则返回false(3)若两棵树都非空,则看下val是否相等,若val不相等则返回false。若val相等则return isSameTree(p->left, q->left) && isSameTree(p->right, q->right);

非递归的就是利用2个queue进行层次遍历,每次进队的时候,把2个node拿来比较一下看是否相等,如果不等就return false


242 Valid Anagram

思路:2种方法


217 Contains Duplicate

思路:多种思路


171 Excel Sheet Column Number

思路:26进制转10进制


169 Majority Element

思路:一个简单的方法就是对数组排序,然后下标为n/2的元素就是要返回的值,因为注意到题目说肯定有一个元素出现的次数超过一半,那么排序后那个元素肯定会出现在正中间(可证明),时间复杂度就是排序复杂度O(nlogn)

当然还有更好的线性算法:每次从数组中找出一对不同的元素,将它们从数组中删除,直到遍历完整个数组。由于这道题已经说明一定存在一个出现次数超过一半的元素,所以遍历完数组后数组中一定会存在至少一个元素。Moore voting algorithm--每找出两个不同的element,就成对删除即count--,最终剩下的一定就是所求的。时间复杂度:O(n) 点击打开链接


235 Lowest Common Ancestor of a Binary Search Tree

思路:由于是一棵二叉搜索树,所以是有序的,那么可以用递归的方法,如果p和q在root的两边,则root就是我们要的点,否则,就分别返回左子树和右子树的递归结果。详情可见:递归&非递归


328 Odd Even Linked List

思路:第一个节点被默认为基数,第二个为偶数,奇偶交错排列,所以分别,取得第一个和第二个节点的指针,当作奇数和偶数的链表头,然后将每个奇数放入奇数链表,偶数放入偶数链表,最后连起来。参考:点击打开链接


206 Reverse Linked List

思路:反转链表,这道题有递归和非递归方法,非递归的方法也可以分为2种,一种是只用到2个迭代指针(详见:2指针),还有一种是用到3个迭代指针(详见:3指针),建议用3个迭代指针的方法,因为2指针的话需要把head头结点也作为一个迭代指针,并且需要在第一次的时候判断一下特殊情况,否则会出现两个指针互相指向对方而出现死循环!!!这里弄得我找了半天才找到,所以建议用p1,p2,p3这3个指针来迭代遍历。


13 Roman to Integer

思路:罗马数字转换为阿拉伯数字,记得从右往左读取判断,遇到最大的之前都累加,如果遇到小的就减去它,详见:点击打开链接


345 Reverse Vowels of a String

思路:反转字符串里的元音字母,和344反转字符串差不多,只不过中途要判断一下是否是元音


191 Number of 1 Bits

思路:其实就是求一个数的二进制数有多少个1,很简单,除K取余法


70 Climbing Stairs

思路:其实就是求斐波那契数列,可以用递归,但是递归超时了,那就用迭代方法,0ms运行时间通关


83 Remove Duplicates from Sorted List

思路:给定一个有序的链表,删除此链表中的重复元素,很简单,就用两个指针p1和p2遍历,p1表示当前节点,p2用来指向下一个节点,如果p1和p2的值相等的话,就把p1的next指针指向p2的下一个节点,细节的地方需要处理一下,代码看:点击打开链接


263 Ugly Number

思路:给如果一个数只包含2、3、5这3个质因子就是丑数,就用一个循环判断,如果不能整除2、3、5就返回false,如果能整除,则再进一步判断,知道最后除尽为1为止。答案请看:点击打开链接


202 Happy Number

思路:循环把一个数字的各个位的数字平方相加,直到结果为1为止,这就是快乐数,如果不满足就不是。注意有个技巧,就是循环判断的时候,如果一个数字循环重复出现了那么这个数肯定就不是快乐数,就可以通过这个条件来终止循环,C++中可以用set表示,把每次产生的数加入set,如果新的数字已经在set中出现了,那就返回false。代码可见:点击打开链接


326 Power of Three

思路:判断一个数是否是3的幂,最笨的方法就是循环判断,但是这种方法会很慢,大概花了160ms运行时间,代码见:点击打开链接。有一个trick技巧,就是不用任何循环,直接return n>0 && 1162261467%n == 0; 就行,因为理论上int值中3的幂的最大值为1162261467,所以所有的3的幂都能够被该数整除。运行时间为128ms


231 Power of Two

思路:判断一个数是否是2的幂,思路和上题类似,循环方法用了8ms,第二种trick就是直接return n>0 && 4294967296%n==0;

还有第三种思路就是从位操作的角度考虑,2的幂用二进制表示,则只有一个位是1,其余全部是0。具体见:http://blog.csdn.net/sunao2002002/article/details/46777615


121 Best Time to Buy and Sell Stock

思路:断一简单的动态规划题,就是找到数组中的最大值-最小值等于多少,并且最小值的下标要比最大值的下标要小。就用一层循环,从前往后遍历,每次都用2个变量来存放记录,一个是min_price,也就是到当前位置为止最小的数。还有一个就是max_profit,max_profit是当前位置的profit(即当前位置的price减去min_price)和历史记录的max_profit中的较大值。代码见:8ms代码


21 Merge Two Sorted Lists

思路:合并2个有序链表,当L1和L2都存在的时候,就挨个判断取出较小的元素加到fakeHead屁股后面,循环完了后,再看下L1和L2还有没有,如果有的话,就继续加到fakeHead屁股后面,然后再返回fakeHead的下一个元素就行。


24 Swap Nodes in Pairs

思路:合在一个链表中,成对的进行反转,比如1234变为2143。思路很简单,就是逐个遍历,利用四个指针,p1 p2 p3 和last指针,逐个的两两交换,每次同时判断2个元素。然后注意前后两对不同pair之间的衔接。


232 Implement Queue using Stacks

思路:合用stack实现Queue的操作,很简单,就用2个栈来模拟队列就行


110 Balanced Binary Tree

思路: 判断一棵树是否是平衡二叉树,即对于树中的任一节点,其左子树和右子树的高度差小于等于1才行。所以这里需要用到一个求树的高度的函数,如下

[cpp]  view plain  copy
 print ? 在CODE上查看代码片 派生到我的代码片
  1. int depth(TreeNode* root) {  
  2.     return root?max(depth(root->left),depth(root->right))+1:0;  
  3. }  
然后再判断是否是平衡树:

[cpp]  view plain  copy
 print ? 在CODE上查看代码片 派生到我的代码片
  1. bool isBalanced(TreeNode* root) {  
  2.     return root?abs(depth(root->left)-depth(root->right))<=1&&isBalanced(root->left)&&isBalanced(root->right):1;  
  3. }  


101 Symmetric Tree

思路:判断一棵树是否是对称的,递归方法只需4ms:点击打开链接。还有一种就是迭代方法,用BFS,用1个队列,也是4ms,详见:点击打开链接


198 House Robber

思路: 这是一道简单的动态规划题,给定一个vector数组,对每个元素相加,求最大的sum是多少,但是不能取连续的2个数,比如一个数组{1,2,3,4,5}取1245是不对的,取135是对的。可以分为很多状态,最简单的状态就是只有2个元素,然后逐步迭代。n个元素中的最大sum是f(n)和f(n-1)中的较大值,f(n)=f(n-2)+n的值,f(n-1)是没有取第n个元素的sum

详情可看代码:点击打开链接


102 Binary Tree Level Order Traversal

思路: 这与简单的层次遍历稍微不同,他需要把每层的单独用个数组存储,然后最后返回一个二维数组,所以需要每次用一个count标记一下。用了4ms,见: 点击打开链接


107. Binary Tree Level Order Traversal II

思路:这与上题类似,只不过需要逆序。由于加了逆序的操作,用了8ms,见:点击打开链接


27 Remove Element

思路:就地删除一个元素,然后返回数组的长度。很奇怪的题目,可以用一个pointer扫描,然后把每个元素往前挪一位,见:点击打开链接


26 Remove Duplicates from Sorted Array

思路:就地删除有序数组里的重复元素,就扫描数组然后就地压缩,见:点击打开链接

342. Power of Four

思路:判断一个数是否是4的幂,第一种最简单的思路就是直接循环判断,整除+求余数,如果余数不等于0就不是4的幂,这种方法运行要9ms。

第二种方法是用log函数,如下所示:

[cpp]  view plain  copy
 print ? 在CODE上查看代码片 派生到我的代码片
  1. return log(num) / log(4) == (int)(log(num) / log(4));  
这种方法很巧妙的利用了log函数的性质,因为只有num是4的幂的时候,log产生的数才会等于整数,否则就是小数。这种方法运行只要8ms。
第三种方法是位操作,运行时间是7ms或者8ms,具体见: 点击打开链接


66 Plus One

思路:简单的大数加法,遍历数组的每位,同时处理进位,如果最后还有进位,则在数组最前面在插入1即可。可参考这篇博客:点击打开链接


118 Pascal's Triangle

思路:杨辉三角形,很简单,找到规律就能写出来,一个数等于他肩上的2数之和,代码见:点击打开链接


172 Factorial Trailing Zeroes

思路:简给定一个数n,求n的阶乘的末尾有几个0,细细一想,求它有多少个0,其实就是求它的质因数有多少个(2*5)的存在,根据归纳法可以证明,一个数的阶乘的质因子中2是远远多于5的,所以只要求它的质因子中有多少个5就行了。


119 Pascal's Triangle II

思路:杨辉三角形,要求出给定的一行,空间复杂度要求为O(k),这题不能用组合数来模拟,因为数字太大会溢出,详情见:点击打开链接


112 Path Sum

思路:求根节点到叶节点的路径和跟指定的number相不相同,有递归和非递归两种方式:点击打开链接


9 Palindrome Number

思路:给定一个整数n,判断是不是回文数,先求出它的reverser number,然后再判断它和原来的n是否相等就行


225 Implement Stack using Queues

思路:用queue来模拟stack,一个queue就行


111 Minimum Depth of Binary Tree

思路:求二叉树的最小深度,注意比起求最大深度多了2个判断条件,一定要注意


160 Intersection of Two Linked Lists

思路:求二个链表的汇合点,假设链表A和B相交,则交点及之后的部分长度是相同的,相差的是交点前的部分。计算A和B的长度差n,较长的那个先走N步,然后和较短的那个同时遍历。如果指针指向同一元素,则为交点,否则A和B 没有交点。具体见:点击打开链接


88 Merge Sorted Array

思路:合并2个有序的数组,从后面往前比较,这样就不需要从前往后移位了,具体见:点击打开链接


36 Valid Sudoku

思路:检查数独是否是合法的,就按照行、列、块分别来模拟就好。


190 Reverse Bits

思路:位运算反转2位数,先用与运算&把最后一位取出来,然后把n右移一位,再把结果result左移一位并和刚取出的最后一位做或预算|,循环32次。只用了4ms,代码见:点击打开链接


219. Contains Duplicate II

思路:位判断数组是否包含两个相同的数,且这2数的下标的差不超过k,一开始暴力求解,时间复杂度为O(n*k),后来可以通过map来实现,加到map的时候判断一下是否已存在,如果存在相同的数,则看下下标之差是否小于等于k,具体见:点击打开链接


223 Rectangle Area

思路:求2个长方形所覆盖的区域面积,其实就是先求2个长方形的面积之和,然后再减去2个长方形的重叠面积。有技巧,具体见:点击打开链接


58 Length of Last Word

思路:求一个字符串所包含的最后一个单词的长度,从后往前遍历,我就用了cctype里的isalpha(c)函数来判断是不是字母,然后就开始计数,记得先处理末尾的空白字符。运行只用了4ms,代码见:点击打开链接


19 Remove Nth Node From End of List

思路:要求删除倒数第n个节点,并且只能扫描一趟,那我就用两个指针扫描,并且让这两个指针相差n个距离,然后同时往后扫描,当第二个指针扫描到末尾的时候,第一个指针所指的元素就是要删除的节点。


20 Valid Parentheses

思路:判断一个字符串里的括号是否是合法的,有大中小三种括号,就用一个栈就行,入栈的时候如果出现了匹配括号就pop,如果最后栈为空,就说明是合法的


205 Isomorphic Strings

思路:判断2个字符串是不是异构体,比如paper和title就是2个异构体,而foo和bar就不是。基本思点击打开链接路就是用2个map,然后最后看得到的2个字符串是否相等。比如paper和title可以转换为字符串12134,并且转换后2者相同的话即为等价。


290 Word Pattern

思路:判断2个先写一个C++的split函数,把一个字符串里的单词分离出来用vector返回,然后再用一个map和一个set建立对应关系,最后运行时间0ms,完美。代码见:点击打开链接


299 Bulls and Cows

思路:字符串的文字游戏,具体可见我的代码:点击打开链接


203 Remove Linked List Elements

思路:删除链表中所有val等于特定val的元素,用2个指针扫描,记得处理头结点的情况,代码见:点击打开链接


38 Count and Say

思路:题意是n=1时输出字符串1;n=2时,数上次字符串中的数值个数,因为上次字符串有1个1,所以输出11;n=3时,由于上次字符是11,有2个1,所以输出21;n=4时,由于上次字符串是21,有1个2和1个1,所以输出1211。依次类推,写个countAndSay(n)函数返回字符串。就用模拟的方法来就好,字符串的处理有点绕,具体请见:点击打开链接


14 Longest Common Prefix

思路:求多个string的最长公共前缀,首先排好序,然后把要返回的字符串设置为排序后的第一个字符串(因为它最短最小),然后只需要2趟循环就可以找出最长公共前缀(最外层循环是第一个字符串的长度,第二层循环是不同的string的个数)。代码运行只需要4ms,具体见:点击打开链接


257 Binary Tree Paths

思路:返回所有从根节点到叶节点的路径,我用DFS递归搞定的,代码运行只需要4ms,具体见:点击打开链接


234 Palindrome Linked List

思路:返回判断一个链表是不是回文串,第一种naive的方法是借助一个stack,申请一个辅助栈结构来存储链表的内容,第一次遍历将链表节点值依次入栈,第二次遍历比较判断是否为回文。需要额外的空间开销O(n),并且需要遍历2趟。考虑时间开销只能为O(n)和空间开销为O(1)的话,可以用反转链表法,将链表后半段原地翻转,再将前半段、后半段依次比较,判断是否相等,时间复杂度O(n),空间复杂度为O(1)满足题目要求。 链表翻转可以参考LeetCode 206 Reverse Linked List的代码。参考:点击打开链接


67 Add Binary

思路:返回判断求2个二进制数的和,所有数字都是以字符串的形式表示的,首先需要处理一下这2个字符串使得它们长度相等,左边空余的地方用0填充,然后从右往左模拟加法,运行时间4ms,代码见:点击打开链接


303 Range Sum Query - Immutable

思路:求指定范围和,且这个操作会执行多次。那么我就设置一个和数组,每次查询的时候只要用sum[j+1]-sum[i]就可以得到那个范围的和了。代码见:点击打开链接


28 Implement strStr()

思路:判断一个字符串s中是否存在子串sub,若存在则返回第一次出现的下标,否则返回-1,我直接调用string的find方法AC了,只要4ms,23333,不过具体要来做的话还是得用字符串匹配的算法来,具体可以看下算法的字符串那一章。4ms伪AC代码见:点击打开链接


7 Reverse Integer

思路:逆转一个数字,虽然简单,但需要考虑多种情况,比如1000的逆序数应该显示为1而不是0001,所以这样就不能用vector一个一个弹弹球了。然后还要考虑溢出的问题,假设输入的数字是100000000000,那么就返回0。代码见:点击打开链接


204 Count Primes

思路:求素数,普通暴力求解的时间开销太大了,得用埃拉脱色尼筛选法,代码见:点击打开链接


6 ZigZag Conversion

思路:求之字形的字符串转换,找规律题目,找到规律代码就出来了,有篇博客讲解的很好,可参见:点击打开链接


125 Valid Palindrome

思路:判断一个字符串是否是回文串,里面包含空格、标点符号等等,要求只是别数字和字母,大小写是等价的。可以用C++的cctype头文件中的isdigit()和isalpha()和tolower()函数来帮助我们,然后把判断逆转字符串和原字符串是否相等来判断。代码见:点击打开链接


228. Summary Ranges

思路:很简单的模拟,就是C++的int转换成string有点麻烦(难怪大家都用Java写,java的内置函数很强大),所以我就自己写了个C++转换函数,具体代码见:点击打开链接


1 Two Sum

思路:一个数组中两个位置上的数的和恰为 target,求这两个位置。暴力求解的时间复杂度是O(n^2),绝壁TLE超时。可以用排序+双指针法,先用一趟排序,然后再用双指针前后往中间扫描,找到后就进行匹配返回,时间复杂度为O(nlogn),运行时间12ms,通过。还有一种方法是用hash,具体见http://blog.csdn.net/hcbbt/article/details/43966403


278. First Bad Version

思路:二分查找的变形,注意一点mid = (left + right) / 2会导致溢出,所以设置mid = left + (right - left) / 2; 代码见:点击打开链接


155 Min Stack

思路:二设计一个栈,需要有min()操作,返回stack的最小值,可以用2个stack来实现,然后每次push的时候比较的时候把最小的元素压入minStack栈,pop的时候看下是不是最小元素被pop出去了,如果是的话,那就把minStack也pop掉。代码见:点击打开链接


168 Excel Sheet Column Title

思路:10进制转换为26进制,除K取余法,注意下标的处理,每次更新要用n = (n - 1) / 26; 代码见:点击打开链接


189 Rotate Array

思路:循环平移数组,用C++的stl内置的iterator可以很方便的实现,代码见:点击打开链接


165 Compare Version Numbers

思路:循比较两个版本号,看哪个大些,比如0.0.1要小于0.1,其实就逐个分区分区比较就好,以小数点分隔开不同的区间,代码见:点击打开链接


8 String to Integer (atoi)

思路:自己写一个string转换为int的函数,有一种作弊的方式,就是用C++的stringstream,代码见:点击打开链接。如果要一步一步来自己写的话,推荐看这个人的代码,写的很好:点击打开链接


141. Linked List Cycle

思路:自己写一判断一个链表是否有循环,可用快慢指针法,两个指针同时遍历,如果两个指针相等的话,那么久有循环,返回true。否则返回false。运行12ms


OK,至此为止,leetcode中easy模式里不需要付费的的80道题已经全部通关了!接下来是Medium模式。请关注我后续的博客,谢谢支持!


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值