1.移除元素
题目:
给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度。
不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并 原地 修改输入数组。
元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。
和昨天的重复排序类似。
思路:单次遍历,并声明一个变量记录当前有效的长度,比较时,如果相等则直接进入下一轮循环,如果不相等,先把当前元素赋值给当前变量下标,然后变量自增1,(顺序不能弄错)
var removeElement = function(nums, val) {
let l = nums.length,
res = 0;
for (let i = 0; i < l; i++) {
if (nums[i] !== val) {
nums[res] = nums[i];
res++;
}
}
return res;
};
没啥优化空间,单次遍历,也没递归,时间复杂度和空间复杂度都是最低了。
2.实现strStr()
题目:
实现 strStr() 函数。
给定一个 haystack 字符串和一个 needle 字符串,在 haystack 字符串中找出 needle 字符串出现的第一个位置 (从0开始)。如果不存在,则返回 -1。
思路:其实就是字符串的indexOf方法,不过咱肯定用原生写。
和冒泡排序十分类似,。
思路:双重循环,依次比较
var strStr = function(haystack, needle) {
let l = needle.length;
if (!l) return l;
let l2 = haystack.length;
if (l > l2) return -1;
for (let i = 0; i < l2; i++) {
for (let j = 0; j < l; j++) {
if (haystack[i + j] !== needle[j]) break;
if (j === l - 1) {
return i;
}
}
}
return -1;
};
问题:每个都遍历,耗时太长
优化方向:提早跳出不必要的循环。可以在外层循环比较haystack剩余字符串长度和needle的长度,如果前者更小,则直接跳出循环返回-1即可。
var strStr = function(haystack, needle) {
let l = needle.length;
if (!l) return l;
let l2 = haystack.length;
if (!l2) return -1;
if (l > l2) return -1;
for (let i = 0; i < l2; i++) {
if (l2 - i < l) return -1;
for (let j = 0; j < l; j++) {
if (haystack[i + j] !== needle[j]) break;
if (j === l - 1) {
return i;
}
}
}
return -1
};
3.搜索插入位置
题目:
给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。
你可以假设数组中无重复元素。
思路:分两种情况,一是有相等的元素,二是没有相等的元素。
相等的情况很容易区分,不相等的时候,可以这样,因为原数组是排序号的,我们一直记录比目标值小的成员的下标即可,最后返回+1的值
let l = nums.length,
j = -1;
for (let i = 0; i < l; i++) {
if (nums[i] === target) return i;
if (nums[i] < target) j = i;
}
return j+1;
优化方向:提前终止循环
let l = nums.length,
j = -1;
if (target <= nums[0]) return 0;
if (target > nums[l - 1]) return l;
for (let i = 0; i < l; i++) {
if (nums[i] === target) return i;
if (nums[i] < target) j = i;
}
return j + 1;
优化方向:二分法查找,而非单次遍历,减少比较次数:
let left = 0;
let right = nums.length - 1;
if (target > nums[right]){ return right + 1; }
if(target<=nums[0])return 0
while (left < right) {
let index = (left + right) >>> 1;//取左中位数
if (nums[index] < target){
left = index + 1;
}else{
right = index;
}
}
return left;
4.外观数列
题目:
「外观数列」是一个整数序列,从数字 1 开始,序列中的每一项都是对前一项的描述。前五项如下:
1. 1
2. 11
3. 21
4. 1211
5. 111221
1 被读作 "one 1" ("一个一") , 即 11。
11 被读作 "two 1s" ("两个一"), 即 21。
21 被读作 "one 2", "one 1" ("一个二" , "一个一") , 即 1211。
给定一个正整数 n(1 ≤ n ≤ 30),输出外观数列的第 n 项。
注意:整数序列中的每一项将表示为一个字符串。
思路:从左到右,双重循环,第一次循环是记录n的值,第二轮循环是遍历上一轮循环的结果,根据上一轮的结果得到这一轮的结果。所以首先需要一个变量保存上一轮的结果,一个变量计算这一轮的结果。
此外,还要有一个变量记录当前遇到的数是什么数,一个变量记录当前数出现的次数
遍历上一轮的结果,比较每一个字符串和当前字符串,如果相同,则变量+1,如果不同,则先对结果拼接,然后更新当前的数,
var countAndSay = function (n) {
if (n == 1) return "1";
let res = "1",
v = "0",
a = 0,
r = "";
for (let i = 1; i < n; i++) {
let l = res.length;
for (let j = 0; j < l; j++) {
if (res[j] !== v) {
if (a) {
r += `${a}${v}`;
}
v = res[j];
a = 1;
} else {
a++;
}
}
if (a) {
r += `${a}${v}`;
}
v = "0";
res = r;
a = 0;
r = "";
}
return res;
};