算法备忘
箴言:
The key is to implement the solution cleanly without dealing with each edge case separately. (关键是要清晰的实现,而不是针对每种边界情况都特殊处理)
写了这么多程序,总结出以下容易出错的地方
- 溢出,不管在程序的哪个部分,都要考虑所做的运算,是否会导致溢出
- 空数组,空链表,空对象,传到函数里的任何参数都有为空的可能,一般都会导致程序bug,需要特别注意是否特殊处理为空的情况
- 传进来的参数是否合法
- 有时候一些题目会让我们做一些变换,需要特别注意变换后的对象是否合法
1.二分搜索(迭代),要根据左右边界(left, right),确定中间位置(middle),每一轮迭代都要更新左右边界,在更新的时候要用到middle,这时候要注意更新方法!
我们要知道,middle的时候是靠左的。这是因为,如果数组元素个数为奇数,那么middle=(left+right)/2肯定能整除,middle位于中间位置,两边数量相等。
但如果数组元素个数为偶数,那么middle=(left+right)/2不能整除,根据Java的除法,middle会偏左。比如,4个元素的数组middle=(0+3)/2=1,就位于第二个位置上
要确保在更新的时候不能漏掉元素,并且要可以跳出循环(跳出循环的条件是left < right,非常重要)。
要更新left,让left=mid + 1;(更新后,可以确保left <= right)
要更新right,让right = mid; (更新后,可以确保left <= right)
这样子,在跳出循环的时候,肯定left==right,返回left或right都行
下面给一个例子,LeetCode上一个题目,Find Peak Element,也就是找到数组中峰值所在位置,如果有多个峰值的话,返回任意一个的位置就ok
代码如下,仔细体会边界更新的写法
public int findPeakElement(int[] num) {
int left = 0;
int right = num.length - 1;
while (left < right) {
int mid = (left + right) / 2;
if (num[mid] < num[mid+1]) {
left = mid + 1;
} else {
right = mid;
}
}
return left;
}
根据上面的思路写出的二分搜索如下:
public int binarySearch(int[] num, int target) {
if (num.length == 0) {
return -1;
}
int left = 0, right = num.length-1;
while (left < right) {
int mid = (left + right) / 2;
if (num[mid] == target) {
return mid;
} else if (num[mid] < target){
left = mid + 1;
} else {
right = mid;
}
}
if (num[left] == target) {
return left;
}
return -1;
}
2.将二维数组的位置信息转化为一维存储!
有时候需要存储二维数组的坐标信息,一般来说可以定义一个Point对象存储坐标,还有一种方法,将二维数组的X,Y转化为一个数字,并且可以还原回去
比如char型二维数组m*n(m行,n列),如果一个坐标为(x,y),那么可以做变换为k = x*n+y,只存储k即可,想要还原时,可以做变换x = k / n; y = k % n;
这样子就可以解决二维存储困难的问题,但代价就是需要额外的计算,这也是用时间换空间的例子
第一种用Point的方案需要额外的对象存储,第二种需要额外的计算
下面以char型数组m[3][4]为例,定义数组行数为int rows = m.length = 3;数组列数为int colums = m[0].length = 4;
如果要记录一个位置(2,1),就可以存储2*4+1=9,这是按行来计算的,每行4个位置,那么这个(2,1)就代表第九个位置(从0开始)
如果按列来计算,可以存储2+1*3=5,在还原的时候,用x = k % m; y = k / m;
3.有些二维数组的不同信息比较少,比如存的都是0或1,在操作这个二维数组的时候,需要标记某些位置不处理,那么可以直接修改这个数组,待操作完毕后再恢复这些位置原来的信息即可。
具体可以参考Leetcode上Surrounded Regions这道题,可以直接在二维数组中标记哪些为'O'的位置不需要处理,比如把这些位置的'O',修改为除了'X',‘O'之外的'P',那么在修改完二维数组之后,再遍历一遍,把值为'P'的位置恢复为'O'
4.今天在做回文判断(不允许使用额外的空间)这道题目的时候,又产生了思维缺陷。想用异或的方法来判断,思路比较简单,当数字有偶数位的时候,如果是回文数,那么对称的位置疑惑为0,最后的异或结果也是0,但如果是奇数位,那么异或的结果是中间那个数字的(比如12321,异或结果就是3)。这里有一个重大缺陷,如果相等的两个数不在对称的位置,那么异或的结果还是0(比如111222),也就是说异或的结果与数字的位置是没有关系的,那么显然就不能用来判断数字是否回文了!!!

浙公网安备 33010602011771号