小编目前在学习算法持续更新,共勉
704. 二分查找
给定一个 `n` 个元素有序的(升序)整型数组 `nums` 和一个目标值 `target` ,写一个函数搜索 `nums` 中的 `target`,如果目标值存在返回下标,否则返回 `-1`。
输入: nums = [-1,0,3,5,9,12], target = 9
输出: 4
解释: 9 出现在 nums 中并且下标为 4
var search = function(nums, target) {
let l = 0, r = nums.length - 1;
// 区间 [l, r]
while(l <= r) {
let mid = Math.floor((l + r) /2);
if(nums[mid] === target) return mid;
let aa = nums[mid] < target;
console.log("isSmall:",isSmall)
l = aa ? mid + 1 : l;
r = aa ? r : mid - 1;
}
return -1;
};
1.因为例子给的是闭合数组所以需要l<=r(闭合数组表示包含-1和12),如果是[1,2)表示只包含了1所那就是l<r
2.因为是二分查找法并且是升序的数组,所以我们需要将数组切成两份,并取中间值mid
3.如果mid刚好是target,那就返回mid当前的下标
4.判断target和中间值谁大谁小。target大于中间值的话说明在后半部分的数组,反之则在前面的数组
5.不断循环,判断条件l和r需要不断的变化。如果在前面的数组,r将不断的-1。反之,l则不断的+1
27. 移除元素
给你一个数组 nums **和一个值 val,你需要 原地 移除所有数值等于 val **的元素,并返回移除后数组的新长度。
不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并 原地 修改输入数组。
元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。
输入: nums = [3,2,2,3], val = 3
输出: 2, nums = [2,2]
解释: 函数应该返回新的长度 2, 并且 nums 中的前两个元素均为 2。
你不需要考虑数组中超出新长度后面的元素。
例如,函数返回的新长度为 2 ,而 nums = [2,2,3,3] 或 nums = [2,2,0,0],
也会被视作正确答案。
var removeElement = function(nums, val) {
let size = nums.length
let left = 0
for(let right = 0;right < size;right++){
if(nums[right] != val){
nums[left] = nums[right]
left++
}
}
return left
};
1.这道题用双指针的解法,让右指针进行循环,大小不超过数组的长度
2.当右指针不等于要删除的元素的时候,将右指针的值赋值给左指针。并且左右指针都自加移动到下一个值
3.当右指针等于要删除的值的时候,左指针不进行操作(因为不要这个值所以不进行赋值)
4.到最后不断赋值,就会将要的值不断的重新往前赋值,返回left
977. 有序数组的平方
给你一个按 非递减顺序 排序的整数数组 nums,返回 每个数字的平方 组成的新数组,要求也按 非递减顺序 排序。
输入: nums = [-4,-1,0,3,10]
输出: [0,1,9,16,100]
解释: 平方后,数组变为 [16,1,0,9,100]
排序后,数组变为 [0,1,9,16,100]
var sortedSquares = function(nums) {
let res = []
for(let i = 0,j = nums.length -1;i<=j;){
let left = Math.abs(nums[i]);
let right = Math.abs(nums[j])
if(left < right){
res.unshift(right * right)
j--
}else{
res.unshift(left * left)
i++
}
}
return res
};
1.这道题可以用for循环暴力破解,再用快排的方式去排序,时间是nlogn,我们这里用双指针的方式,时间是On
2.首先定义2个指针分别在头尾(因为这是升序的数组,所以平方之后的大小只会在两边进行比对)。
3.开始循环,让左右两边都进行绝对值,比较左右两边的大小。如果是右边的大,则将右边平方放进新数组,并且j--,如果是左边的大则将左边平方放进数组,并且i++。
4.返回新数组
209. 长度最小的子数组
给定一个含有 n 个正整数的数组和一个正整数 target
找出该数组中满足其和 ≥ target 的长度最小的 连续子数组 [numsl, numsl+1, ..., numsr-1, numsr] ,并返回其长度 。 如果不存在符合条件的子数组,返回 0 。
输入: target = 7, nums = [2,3,1,2,4,3]
输出: 2
解释: 子数组 [4,3] 是该条件下的长度最小的子数组。
var minSubArrayLen = function(target, nums) {
let i = sum = 0
//result不可能会大于数组长度,所以可以拿来判断是否会出现数组之和小于target
let result = nums.length + 1
for(let j = 0;j < nums.length;j++){
sum += nums[j]
while(sum >= target){
let a = j - i + 1
result = Math.min(result,a)
sum = sum - nums[i]
i++
}
}
return result > nums.length ? 0 : result
};
1.这道题的思路用的是滑动模块也可以说是双指针
2.首先定义2个指针都是第一位,开始循环,这次我们循环的是右指针,定义一个sum。sum为连续子数组的和,当sum大于等于target的时候,进入下一次循环
3.这里为啥用循环而不是用if呢,这里就是滑块的思维。当sum大于target时,result就是当前子数组的长度,然后开始让左指针++,sum也开始减去nums[i],如果这个时候还大于target,i继续自加一直到小于target的时候才出循环,然后让右指针自加,所以这里不能用if,不然滑不起来
4.result要去最小值,所以要用min去比较,这里要注意为什么result要等于数组长度加1呢,因为有可能整个数组加起来都小于target,所以在最后return的时候进行判断,如果一直都小于target那就要返回0了
242. 有效的字母异位词
给定两个字符串 s 和 t ,编写一个函数来判断 t 是否是 s 的字母异位词。
注意:若 s 和 t 中每个字符出现的次数都相同,则称 s 和 t 互为字母异位词。
输入: s = "anagram", t = "nagaram"
输出: true
function aaa(s, t) {
if (s.length != t.length) return false
const resSet = new Array(26).fill(0);
const base = "a".charCodeAt();
for (const i of s) {
resSet[i.charCodeAt() - base]++;
}
for (const i of t) {
if (resSet[i.charCodeAt() - base]==0){
console.log("resSet[i.charCodeAt() - base]:",resSet[i.charCodeAt() - base]);
return false;
}
resSet[i.charCodeAt() - base]--;
}
return true;
}
console.log(aaa("ana","aaa"))
1.这道题的思路主要是先将s数组在reSet数组中放置,每有一个同样的就加1。再把t数组的去搜索--。
2.当t数组在reSet数组中找不到>0的情况,那就说明这两个数组不是有效的字母异位词。
349. 两个数组的交集
给定两个数组 nums1 和 nums2 ,返回 它们的交集 。输出结果中的每个元素一定是 唯一 的。我们可以 不考虑输出结果的顺序 。
输入:nums1 = [1,2,2,1], nums2 = [2,2]
输出:[2]
输入:nums1 = [4,9,5], nums2 = [9,4,9,8,4]
输出:[9,4]
解释:[4,9] 也是可通过的
const set_intersection = (set1, set2) => {
if (set1.size > set2.size) {
return set_intersection(set2, set1); //先确定好哪边的长度长
}
const intersection = new Set();
for (const num of set1) { //拿短的来遍历节省时间
if (set2.has(num)) {
intersection.add(num);
}
}
return [...intersection];
}
var intersection = function(nums1, nums2) {
const set1 = new Set(nums1);
const set2 = new Set(nums2);
return set_intersection(set1, set2);
};
console.log(intersection([1,2,2,1],[2,1,3]))
1.首先确定num1长还是num2长,确定之后,遍历短的数组,判断是否是否在长的数组里面,有则add,最后返回数组
202. 快乐数
编写一个算法来判断一个数 n 是不是快乐数。
「快乐数」 定义为:
对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和。 然后重复这个过程直到这个数变为 1,也可能是 无限循环 但始终变不到 1。 如果这个过程 结果为 1,那么这个数就是快乐数。 如果 n 是 快乐数 就返回 true ;不是,则返回 false 。
输入:n = 19
输出:true
解释:
1² + 9² = 82
8² + 2² = 68
6² + 8² = 100
1² + 0² + 0² = 1
输入:n = 2
输出:false
var isHappy = function (n) {
let a = new Map()
while(true){
if(a.has(n)) return false;
if(n == 1) return true;
a.set(n,1)
n = getNum(n)
}
function getNum(num){
let sum = 0
while(n){
sum += (num % 10) ** 2
n = Math.floor(n / 10)
}
return sum
}
}
console.log(isHappy(123));
1.首先题目说了可能是无限循环,但始终不会是1,就说明了要先无限循环,在进行条件判断return 2.总共2种结果,一种是出现过的数字(既然之前出现过了说明就开始无限循环了),一种是快乐数 3.定义一个map类型,判断是否存在,存在就return false,不存在就存进去,并且调用getNum方法 4.getNum方法主要是进行n的算法去平方和 5.返回结果