很多人都在推荐LeetCode,于是昨天晚上临睡前上去看了一下。因为住的地方网速太捉急,打开扫描了一下题目。发现链表二叉树字符串比较多,相比于SOJ上面随便点开一个就是DP那种无从着手的赶脚好多了。于是注册了一个账号准备练练手,一上来就选了第一道字符串的题目,然后一直WA,当时太晚了,人也迷糊,WA了几次之后什么都理不清了,于是就睡了。 我觉得上面的题目还是比较不错的,虽然不像ACM那样对数学要求比较高,考查的方面还是挺全的。我会花费一些时间把每道题的思路写下来。这并不会花费我太多时间但是可以让我理解更深。OJ网址是oj.leetcode.com。邮箱注册或直接github绑定都行。鉴于题目比较多,我决定10道题目左右写一篇博客,代码我会混用C++或者python,因为有些题用python简直太简单了=_=,希望自己能在一到两个月时间内做完这150题。
1.single number
Given an array of integers, every element appears twice except for one. Find that single one.
Note:
Your algorithm should have a linear runtime complexity. Could you implement it without using extra memory?
题目大意是给一个数组,这个数组中的数分为两种,一种是出现两次的,一种是只出现一次的。而出现一次的数只有一个。要求是在O(n)时间复杂度内,且不用额外空间找出这个数。能不能遍历一遍数组就找到满足条件的数,事实上是可行的,但是这要花费额外的空间,所以又不要额外空间又要在O(n)时间内找到这个数是很难的。这道题考查的是异或运算,如果你知道异或运算,那么这道题非常简单。简单介绍一下异或运算,相信大学学过数电这门课肯定还记得那些门吧,离散数学也应该讲过异或运算(XOR)。异或运算的基本公式是: A xor A = 0 , A xor 0 = A . 1 xor 0 = 1, 0 xor 0 = 0,1 xor 1 = 0.
在计算机中对两个整数进行异或操作就是先将10进制转化为2进制数,然后对每一位进行异或操作,然后将结果在转换成10进制。了解到异或操作之后,这道题就很好解了。不妨设有m对相同的数,有一个只出现一次的数,则一共有2m+1个数,那么那m对数进行异或运算之后肯定等于0,再和剩下的数异或就得到只出现一次的数。Python代码如下:
def singleNumber(self, A): ans = 0 for i in range(0, len(A)): ans ^= A[i] return ans
2.Maximum Depth of Binary Tree
Given a binary tree, find its maximum depth.
The maximum depth is the number of nodes along the longest path from the root node down to the farthest leaf node.
题目大意是找出二叉树的最大深度,最大深度指的就是从根节点到叶结点的最大长度。这道题用递归很简单也很好理解。如果树为空就返回0,否则就返回1+左子树和右子树中深度较大的。C++代码如下:
int maxDepth(TreeNode *root) { return root ? 1 + max(maxDepth(root->left), maxDepth(root->right)) : 0; }
3.Reverse Integer
很简单的反转数字,初学者肯定会遇到的题,直接模拟过程就行了。C++代码如下:
Reverse digits of an integer.
Example1: x = 123, return 321
Example2: x = -123, return -321
int reverse(int x) { int n = 0; while (x) { int t = x % 10; n = n*10 + t; x = x/10; } return n; }
4.Merge Two Sorted Lists
Merge two sorted linked lists and return it as a new list.
The new list should be made by splicing together the nodes of the first two lists.
这道题是考查单链表的归并,给定两个有序单链表,要求将两个链表合并为一个链表,如果理解了归并排序中归并的过程,模拟归并过程即可。但是这道题可以用一个非常简便的方法:递归,对于每次操作来说,我们找到两个链表中较小结点,把它接到前一个结点的next链上,并且指针后移,递归地处理,最后就得到了归并好的链表。C++代码如下
ListNode *mergeTwoLists(ListNode *l1, ListNode *l2) { if(l1 == NULL) return l2; if(l2 == NULL) return l1; if(l1->val < l2->val) { l1->next = mergeTwoLists(l1->next, l2); return l1; } else { l2->next = mergeTwoLists(l2->next, l1); return l2; } }
5.Merge Sorted Array
Given two sorted integer arrays A and B, merge B into A as one sorted array.
Note:
You may assume that A has enough space (size that is greater or equal to m + n) to hold additional elements from B. The number of elements initialized in A and B are m and n respectively.
归并两个有序数组,但是归并后的结果要存在数组A中,如果从前往后归并就很麻烦,一个很好的办法就是从后往前归并。理解归并过程就行。C++代码如下:
void merge(int A[], int m, int B[], int n) { int i = m -1; int j = n -1; int k = m + n -1; while (i >=0 &&j >= 0) { if (A[i] > B[j]){ A[k--] = A[i--]; } else{ A[k--] = B[j--]; } } while (j >= 0) A[k--] = B[j--]; }
6.Sqrt(x)
Implement int sqrt(int x).
Compute and return the square root of x
实现开平方操作,如果一个数不是完全平方数就返回离他最接近的完全平方数。用牛顿法或者二分法都可以实现。我给出一种更加一般地求一个正实数的开方的方法,这里我设置的迭代上限次数是100次,我们可以手动精度e,使结果更加准确。Python代码如下:
二分法:
def BiSqare(x, e): assert x >= 0, str(x) assert e >= 0, str(e) low = 0 high = max(x, 1) //这里high = max (x, 1)是为了求小于1的数的开方 guess = (low + high) / 2.0 count = 1 while abs(guess**2 - x) > e and count < 100: if guess ** 2 < x: low = guess else: high = guess guess = (low + high) / 2.0 count += 1 assert count <= 100 return guess
牛顿法:
def NWSqare(x, e): assert x >= 0 assert e > 0 x = float(x) guess = x / 2.0 guess = 0.001 diff = guess ** 2 - x count = 1 while abs(diff) > e and count <= 100: guess = guess - diff/(2.0 * guess) diff = guess ** 2 - x count += 1 assert count <= 100 return guess