一、栈与队列
1. 用两个栈实现队列
总是出现这样的问题,对数组进行增删查改的过程中,因为数组是动态变化的,所以需要提前保留length的长度,预先定义好个数。否则会出问题,而且还会觉得自己是写的是对的。
题解感悟:其实数据不需要来回倒,因为右边的stack有已完成倒序的元素,只需要从左到右倒。
2. 包含min函数的栈
看完题目之后准备用一个min作为标记,直接记录栈内的最小元素。后来看了题解,发现这样的想法不可行,如果那个最小的元素被pop出去了,但是min记录却不能回退了,所以需要使用一个数组来记录历时最小值,这样可以随时后退。题解用的是辅助栈,但是辅助数组应该也可以。
特别注意:当push一个与当前最小值相同的节点,该最小值也需要同时push到辅助栈里。
二、链表(简单)
1. 从尾到头打印链表
利用辅助的空间(比如说栈、数组),这样的想法还挺简单。用递归就很绝,唉,递归和DP一直是我的短板,无语。
2. 反转链表
写题的时候大概知道,需要暂存一下当前节点的next,并且还需要记录当前节点,以便于之后朝着前面指的时候找的到数据。(我的脑子:&!*&$%)
题解:先暂存后继节点tmp,然后修改链表节点的指向,使用pre暂存当前节点,访问下一节点。
3. 复杂链表的复制
没解,这题有点(unexpectedly)的复杂。
三、字符串(简单)
1. 替换空格
s.replace(/ /g, "%20");
或许需要复习一下正则表达式呢!正则表达式不要背
2. 左旋转字符串
var ns1 = s.substring(n);
var ns2 = s.slice(0, n);
四、查找算法(简单)
1. 数组中重复的数字
优秀的解法(原地交换/而非暴力)是将nums[index]的值交换到数组中所对应的位置,比如说这里的2,就要被交换到nums[2]上,但是这题不能用for循环解,因为不能保证当前交换得到的值的index是对应的,所以要用while循环,保证每次当前的值是一一对应的。
2. 在排序数组中查找数字
利用二分找前后数字的边界,当找last position的时候需要(i+j+1)>>1,这个题解的代码很清楚。不知道为什么现在题解的代码总是很短,很简洁。逻辑写清楚难道不是更容易理解吗?又不是在比谁的代码短???
/**
* @param {number[]} nums
* @param {number} target
* @return {number}
*/
var search = function(nums, target) {
if(nums.length == 0){
return 0;
}
var start = findFirstPosition(nums, target);
if(start == -1){
return 0;
}
var end = findLastPosition(nums, target);
if(end == -1){
return 0;
}
return end-start+1;
};
function findFirstPosition(nums, target){
var i = 0, j = nums.length-1;
while(i < j){
let mid = (i+j)>>1;
if(nums[mid] < target){
i = mid+1;
}else if(nums[mid] == target){
j = mid;
}else if(nums[mid] > target){
j = mid-1;
}
}
if(nums[i] == target){
return i;
}else{
return -1;
}
}
function findLastPosition(nums, target){
var i = 0, j = nums.length-1;
while(i < j){
let mid = (i+j+1)>>1;
if(nums[mid] < target){
i = mid+1;
}else if(nums[mid] == target){
i = mid;
}else if(nums[mid] > target){
j = mid-1;
}
}
if(nums[j] == target){
return j;
}else{
return -1;
}
}
2. 0~n-1中缺失的数字
比上一题简单,只需要一次二分查找就可以了。
五、查找算法(中等)
1. 二维数组的查找
找到一个点,它的两个方向(可以是左-下/或者是右-上)一边增大,一边减小,类似于二叉搜索树,这两个点就是左下角和右上角,可以选择从这两个点开始进行搜索。
2. 旋转数组的最小数字
首先需要分析一下题目:可能存在重复元素的有序数组。重复这两个值让这道题变得没有那么简单了。还是想到要用二分去做,但是有一个问题,如何收缩二分的区间,有三种情况:
需要证明当nums[m] == nums[j]的时候,j=j-1可以有效的缩小区间范围。
- [1, 0, 1, 1, 1]:旋转点 x = 1,m = 2, 当执行 j = j - 1的时候,旋转点还落在区间里。
- [1, 1, 1, 2, 3, 1] :旋转点 x = 4,m = 2,当执行 j = j - 1的时候,旋转点丢失。但这无所谓,因为之前的nums[m] == nums[j],虽然把后面的1丢掉了,但是在前面还有保留,相当于在数组[[1, 1, 1, 2, 3]继续寻找最小值,也总能找到1。