338. Counting Bits
思路:计算一个10进制数的2进制表示中含有多少个1,有2种方法,一种是bit manipulation,另一种是简单的dynamic programming。代码见:http://www.cnblogs.com/coderworld/p/leetcode-countingbits.html
136. Single Number
思路:一个数组中,每个数字都出现了2次,只有一个数字出现了1次,要求找到那个数。我一开始想到的方法是用扫描数组添加到set中,如果出现了2次就从set中erase掉,扫面完后set中唯一一个元素就是我们需要的返回值,写完代码AC结果发现要84ms,超级慢。然后我在搜了搜,发现有种20ms就AC的方法,那就是利用异或操作^,a^a=0, a^0=a,根据交换律a^b=b^a,比如3^4^3=4,根据异或操作的这种性质,我们可以将所有元素依次做异或操作,相同元素异或为0,最终剩下的元素就为Single Number。时间复杂度O(n),空间复杂度O(1)。代码见我
347. Top K Frequent Elements
思路:找出一个数组中出现次数最多的K个数。可以考虑用priority_queue,假如元素是<int, int>这种pair形式,那么优先队列就是按着key的降序进行的,所以队首一定是key最大的元素。这样从优先队列中pop出前K个元素,就可以得到结果了。不过问题是怎样把数组中的元素加到优先队列中。所以我们需要对数组做一次预处理,即统计每个数字出现的次数。可以用map,但是我选择用unordered_map,因为unordered_map是无序的,map是有序的,所以插入元素时unordered_map会快很多。最后代码运行36ms 如果用map的话,那就是60ms了。
260. Single Number III
思路:前面做了只有一个出现一次的数,其他都是出现两次,思路和那题一样。只是这个先将所有数一起异或,然后得到的结果将是两个只出现一次数的异或。也就是说最后得到的数字是a ^ b,而我们需要的是a和b而不是a和b的异或。那如何将a和b从(a^b)中分离呢?比如a是5(101),b是3(011),那么(a^b)就是6(110),观察一下6,6的第二位为1说明a和b在第二位肯定不同,然后就可以根据与这个位的数是否为0将数组分为两半,并且a和b肯定会被分别分开到这两个数组中。这样问题就回到了上题的思路,只要让子数组内元素全部异或一下,得到的两个数就是最终要的只出现一次的数。这段话可能有点绕,需要好好琢磨琢磨一下。判断1在哪一位就用0x01循环的去做&运算就好。代码只需要16ms
238. Product of Array Except Self
思路:解法比较巧妙。由于output[i] = (x0 * x1 * ... * xi-1) * (xi+1 * .... * xn-1)。因此执行两趟循环:
第一趟正向遍历数组,计算x0 ~ xi-1的乘积
第二趟反向遍历数组,计算xi+1 ~ xn-1的乘积
运行时间64ms
122. Best Time to Buy and Sell Stock II
思路:解法比较巧妙。题目说明可以多次买卖,但是同一时间只能有一股在手里。 这样就可以在每次上升子序列之前买入,在上升子序列结束的时候卖出。相当于能够获得所有的上升子序列的收益。 而且,对于一个上升子序列,比如:5,1,2,3,4,0 中的1,2,3,4序列来说,
对于两种操作方案:
一,在1买入,4卖出;
二,在1买入,2卖出同时买入,3卖出同时买入,4卖出;
这两种操作下,收益是一样的。 所以算法就是:从头到尾扫描prices,如果i比i-1大,那么price[i] – price[i-1]就可以计入最后的收益中。这样扫描一次O(n)就可以获得最大收益了。
运行时间为8ms
319. Bulb Switcher
思路:这是一道数学题。大概解释一下,当一个灯泡被执行偶数次switch操作时它是关着的,当被执行奇数次switch操作时它是开着的,那么这题就是要找出哪些编号的灯泡会被执行奇数次操作。将灯泡编号为1到n,第i个灯泡会在第d轮被switch,当且仅当d能整除i(i % d == 0)。所以第i个灯泡只有当switch了奇数次后,它才会亮着。
而一个数的质因数是成对存在的。比如12,它能被1、12、2、6、3、4整除,并且12被switch了偶数次,所以最后还是灭着的。所以问题就转变成了求一个数的质因子数有多少个。再来看下36,36有质因数1、36、2、18、3、12、4、9.还有2个6.所以它的distinct的质因数是奇数个,它最后会亮着。
可以发现规律,只有当i它是一个平方数的时候,第i个灯泡最后会亮。所以问题就变成了求1到n范围内的平方数有多少个。
所以直接用sqrt(n),就可以求出1到n范围内的平方数的数目了。这道题真是考数学和智商啊23333
343. Integer Break
思路:一个数,把它分为至少2个数的和的形式,然后求分解的各个数的乘积的最大值。比如9=3+3+3,9=4+5.但是3*3*3=27是大于4+5的,所以最后返回27.这道题也是一道数学找规律题。可以尝试着手写2到12之间的数字。然后发现的规律就是把每个数分解为3+3+···+2+···+2的形式是最优的。并且3的数目要尽量的多,只有当不能取够3的时候,再去取2.代码可见:0ms
268. Missing Number
思路:求一个数组中少了哪个数,比如[0,1,3]里面少了2,数组里的数都是distinct的,数组的长度如果是3,那么就从0到3里挑3个数存入数组,然后让你找少了哪个数。有2种方法可以AC。
第一种是数学方法:可以先求0到n的和,然后求数组的sum,然后把他们一相减,得到的数字就是答案。运行时间32ms
第二种是bit位操作:利用异或的性质。把数组里的每个数和下标以及数组长度连环做异或。那么得到的就是答案。运行时间36ms
比如0^1^3 ^0^1^2^3 = 2,2就是缺少的那个数,也就是答案。
144. Binary Tree Preorder Traversal
思路:二叉树先根遍历。有递归和非递归2种方式,递归很简单:0ms
非递归就是利用一个stack,不过记得每次是先把右节点push进来,然后再push左节点。时间也是0ms
318. Maximum Product of Word Lengths
思路:在一个字符串组成的数组words中,找出max{Length(words[i]) * Length(words[j]) },其中words[i]和words[j]中没有相同的字母。
方法就是先把每一个单词编码为26位的二进制数,比如abcd就是00000000000000000000001111,abce就是00000000000000000000010111。然后,两两之间互相比较,如果位与运算为0,则说明两者没有共同字母,则可以进行乘法。然后在这两层循环的过程中不断更新最大值,循环结束后就得到返回值了。时间复杂度为O(n*n)。运行时间为128ms
94. Binary Tree Inorder Traversal
思路:二叉树中序遍历。有递归和非递归2种方式,递归很简单:3ms
非递归就是利用一个stack,对于任一结点P,
1)若其左孩子不为空,则将P入栈并将P的左孩子置为当前的P,然后对当前结点P再进行相同的处理;
2)若其左孩子为空,则取栈顶元素并进行出栈操作,访问该栈顶结点,然后将当前的P置为栈顶结点的右孩子;
3)直到P为NULL并且栈为空则遍历结束
时间0ms
可参考:http://www.cnblogs.com/dolphin0520/archive/2011/08/25/2153720.html
12. Integer to Roman
思路:整数转换为罗马数字。分析罗马数字的规律。就把罗马数字和对应的整数存入数组,然后逐个循环遍历。
我们现在拿到一个数N 我们就去表里面找不超过它的最大的数x, 然后把它入我们的输出字符串中,然后将数N-=x, 继续执行这个操作,直到N=0。运行时间32ms
230. Kth Smallest Element in a BST
思路:求二叉查找树的第k个最小元素。注意到二叉查找树的中序遍历结果是有序的,可以利用这个性质来输出结果。用递归的方法做24ms
137. Single Number II
思路:一个数组中,除了一个数之外,其他全部元素都出现了3次,找出那个数。我用的很简单暴力的方法,就是先直接全部存入unordered_map中(因为不用排序,比map要快),key是每个元素的值,value是每个元素出现的次数。然后再遍历整个map,找出value不为3的元素,返回就是答案了,运行28ms 还有一种是位运算,但是我没搞懂,希望有大神能给我讲解一下
96. Unique Binary Search Trees
思路:一个典型的动态规划题,后面的计算依赖于前面产生的结果。假如当前根节点是A,则这棵树的二叉树的数目为#(左子树)×#(右子树),而根据二叉查找树的规律,左子树跟右子树是互相没有交集的,并且左子树的任意元素的值都要小于右子树的任意元素的值。以一个count数组来表示共有i个节点时,能产生的BST树的个数。
n == 0 时,count(0) = 1,
n == 1 时,count(1) = 1,因为只有1这个根节点,数量也为1。
n == 2 时,分2种情况考虑,一种是根为1,另一种是根为2.
n = 2; 1__ __2
\ /
count[1] count[1]
count(2) = count(0) × count(1) + count(1) × count(0) = 2
n == 3 时,分3种情况考虑,根分别为1、2、3,
count(3) = count(0) × count(2) + count(1) × count(1) + count(2) × count(0) = 5
同时,当根节点元素为 1, 2, 3, 4, 5, ..., i, ..., n时,基于以下原则的BST树具有唯一性: 以i为根节点时,其左子树构成为[0,...,i-1],其右子树构成为[i+1,...,n]构成
因此,count[i] = sigma(count[0...k] × count[k+1...i]) 0 <= k < i - 1
所以只要找到规律,就能0ms通过
35. Search Insert Position
思路:二分查找,但是需要变下型,因为其实这个问题是等价于找lower bound,所以每次就把left+1,9ms过
108. Convert Sorted Array to Binary Search Tree
思路:把一个有序数组转换为平衡二叉搜索树。还是用二分查找递归构造,每次选择中点作为root,然后左子树就递归的用左半边数组,右子树就递归的用右半边数组。运行时间20ms
337. House Robber III
思路:https://leetcode.com/discuss/91899/step-by-step-tackling-of-the-problem
22. Generate Parentheses
思路:见CC150的9.6
78. Subsets
思路:详见:http://www.cnblogs.com/felixfang/p/3775712.html 递归的话可以参考九章算法的模板
90. Subsets II
思路:同上
46. Permutations
思路:最简单的是用C++的next_permutation函数去实现,记得先排序一下。12ms过。此外,自己实现的话,有递归和迭代两种方式,细细观察,可以从头开始找规律。
47. Permutations II
思路:受到这个解法的启发,以及这个博客的4种生成全排列的算法。这道题也可以用C++的next_permutation函数去AC过。我还是选择了用全排列树去AC,不过注意的是,如果2个需要交换的数相等的话或者要交换的数已经在set中,就不用交换了。40ms过的
74. Search a 2D Matrix
思路:二维数组里进行二分查找,记得用下标把二维转换为一维,此外注意以下几点,否则会造成死循环:记得在外层循环的判断条件里写left <= right,如果写的是left < right的话,就不会到达最右边的值。然后记得每次二分后left = mid +1 和right = mid - 1。1ms过