2. 合并两个有序数组
相当于nums1长度变大;因为是有序的两个数组 谁大谁往后放;比较完最小长度 如果nums2还有剩余插到中间的空里
var merge = function(nums1, m, nums2, n) {
let k = m + n -1
m = m-1
n = n-1
while (m>=0 && n>=0){
if(nums2[n]>nums1[m]){
nums1[k] = nums2[n]
n--;
}else{
nums1[k] = nums1[m];
m--
}
k--;
}
while (n>=0){
nums1[k] = nums2[n]
k--;
n--;
}
return nums1;
};
3. 两数之和
巧用map存储已经遍历的值
var twoSum = function(nums, target) {
let tempMap = new Map()
for(let i=0;i<nums.length;i++){
if(tempMap.has(target - nums[i])){
return [tempMap.get(target - nums[i]), i]
}else{
tempMap.set(nums[i],i)
}
}
return false;
};
13. 三数之和
var threeSum = function(nums) {
// 先排序
nums.sort((a, b) => a - b);
const result = [];
// nums.length - 2
for (let i = 0; i < nums.length - 2; i++) {
// 重复的跳过
if (i > 0 && nums[i] == nums[i - 1]) continue;
let left = i + 1;
let right = nums.length - 1;
while (left < right) {
const sum = nums[i] + nums[left] + nums[right];
if (sum === 0) {
// 找到符合值存储 然后左右都跳过重复的 继续下一次循环
result.push([nums[i], nums[left], nums[right]]);
while (nums[left] === nums[left + 1]) left++;
while (nums[right - 1] === nums[right]) right--;
left++;
right--;
} else if (sum < 0) {
// 小于目标值左+
left++;
} else {
// 大于目标值右-
right--;
}
}
}
return result;
};
5. 最大子数组和
两个值分别存储累加值和最大值;累加后和当前值比 如果不大于累加值 则使用当前值
var maxSubArray = function(nums) {
let currentMax = nums[0]//存储累加值
let globalMax = nums[0]// 存储最大值
for(let i=1;i<nums.length;i++){
// 累加和 + 当前值 如果大则取当前值的和 否则用当前值
currentMax = Math.max(currentMax+nums[i], nums[i])
// 累加值与最大值比较
globalMax = Math.max(currentMax, globalMax)
}
return globalMax;
};
9. 全排列
全排列没有重复项
var permute = function(nums) {
const result = []
// 参数: 当前已经排列的数组
function backTrack(currents){
// 如果当前排列的数组长度已经和要排列的数组长度一致 则算是一种排列方式
if(currents.length === nums.length){
result.push([...currents]);
return
}
// 1.遍历要排列的数组
for(let num of nums){
// 2.如果已经在当前排列数组内部则进行下一个
if(currents.includes(num)){
continue;
}
// 3.把不在当前数组内的数 添加到当前排列数组里
// 4.继续调这个排列方法;再继续挨个数试
backTrack([...currents,num])
}
}
backTrack([])
return result;
};
41. 组合总和 === target
var combinationSum = function(candidates, target) {
const result = []
candidates.sort((a, b) => a - b); // 首先对数组进行排序
function backTrack(remaining, path, start){
if(remaining==target){
// 推入副本
result.push([...path]);
return
}
for(let i=start; i<candidates.length;i++){
if (remaining+candidates[i] > target) {
// 如果当前值大于剩余值,不需要继续探索
break;
}
// 继续探索
backTrack(remaining+candidates[i],[...path,candidates[i]],i)
}
}
backTrack(0,[], 0)
return result;
};
71.n个骰子的点数
// 回溯
var dicesProbability = function(n) {
let rt = {} // 存各种点数
let cont = 0 // 存总次数
function dfs(oNum) {
// 如果个数够了 证明是一次随机 记录当前点数 并且次数++
if(oNum.len == n){
// 重复的直接+1
if(rt[oNum.rt]){
rt[oNum.rt] += 1
} else{
rt[oNum.rt] = 1
}
cont++;
return
}
for(let i = 1; i < 7; i++){
// 循环6个点数 每个骰子都 六种可能
dfs({
len:oNum.len + 1,
rt:oNum.rt + i
})
}
}
dfs({len:0, rt:0})
let rtArr = Object.values(rt)
return rtArr.map(num=>{
return num/cont
})
};
16. 数组中的第K个最大元素
var findKthLargest = function(nums, k) {
// 第k大个元素 就是从小排序的倒数第几个元素 nums.length - k
return quickSelect(nums, 0, nums.length - 1, nums.length - k);
};
// 要排序的数组 最小 最大 第几个
function quickSelect(nums, low, high, k) {
const pivot = nums[Math.floor((low + high) / 2)];
let left = low;
let right = high;
while (left <= right) {
// 左侧的比中间值小的
while (nums[left] < pivot) left++;
// 右侧的比中间值大的
while (nums[right] > pivot) right--;
// 如果还没相遇 两个互换
if (left <= right) {
[nums[left], nums[right]] = [nums[right], nums[left]];
left++;
right--;
}
}
// 如果目标在 right侧的左边;去最低值和right的区间找
if (k <= right) return quickSelect(nums, low, right, k);
// 如果目标在 left侧的右边;去left和最高值的区间找
if (k >= left) return quickSelect(nums, left, high, k);
return nums[k];
}
21. 长度最小的子数组 === target
双指针;初始化最小值为Infinity; 先加到大于等于target值 再缩短长度,再继续加 记录最短长度
// 先加到target值 再缩短长度,再继续加 记录最短长度
var minSubArrayLen = function(target, nums) {
let left = 0;
let result =0;
let minLen = Infinity
for(let i=0;i<nums.length;i++){
result +=nums[i];
// 和 大于等于 target 开始缩短
while (result>=target){
minLen = Math.min(minLen, i-left+1)
result -= nums[left]
left++
}
}
return minLen === Infinity ? 0 : minLen;
};
80.和为s的连续正数序列
var findContinuousSequence = function(target) {
const max = target - 1, // 可选的最大正数范围 [1, max]
queue = [], // 单调递增队列
res = [] // 结果集
let sum = 0
for (let v = 1; v <= max; v++) {
// 一次将范围值入队
sum += v, queue.push(v)
// 当大于期望值target 时 出队且更新sum
while (sum > target) sum -= queue.shift()
// 当满足条件 存入结果集
if (sum === target && queue.length >= 2) res.push([...queue])
}
return res
};
72.0~n-1中缺失的数字
var missingNumber = function(nums) {
let left = 0;
let right = nums.length-1;
let mid = 0
while (left<=right) {
mid = Math.floor((left+right)/2)
if(mid==nums[mid]){ // 如果对应上 缺失的肯定在右边;左指针移动
left = mid + 1
}else{
right = mid -1 // 如果对应不上 缺失的肯定在左边;右指针移动
}
}
return left // left是满足条件的最小索引
};
let nums = [0,1,2,3,4,5,6,7,9]
37. 寻找重复数
var findDuplicate = function(nums) {
let low = 1;
let high = nums.length - 1;
while (low < high) {
const mid = Math.floor((low + high) / 2);
let count = 0;
// 计算数组中有多少个数小于等于 mid
nums.forEach((num) => {
if (num <= mid) {
count++;
}
});
// 根据抽屉原理缩小搜索范围 如果count大 证明重复数在左边
if (count > mid) {
high = mid;
} else {
low = mid + 1;
}
}
// low 和 high 相遇的地方就是重复的数字
return low;
};
29. 将数组分成和相等的三个部分
给你一个整数数组
arr
,只有可以将其划分为三个和相等的 非空 部分时才返回true
,否则返回false
。先看总数能不能被3整除; 然后得到每份多大值;循环的时候 得到target 计数 计数满足后 返回true 否则返回false
var canThreePartsEqualSum = function(arr) {
let totalSum = arr.reduce((a,b)=>a+b)
// 首先看总和能不能被3整除
if(totalSum%3!==0) return false;
// 每一块的值
let partSum = totalSum/3
let sum = 0, parts = 0;
for(let num of arr){
sum +=num;
if(sum === partSum){
parts++;
sum =0;
}
// 如果计算两部分 后一部分基本可以确定的 但是如果是 [-1,1,-1,1]这种会有问题 也可以当作一个优化项
if(parts === 3)return true;
}
return false;
};
31. 最长连续递增序列
给定一个未经排序的整数数组,找到最长且 连续递增的子序列,并返回该序列的长度。
重点是连续。如果不连续了 累加器=1 连续了就一致+;最大值每次比较
var findLengthOfLCIS = function(arr) {
if (arr.length === 0) return 0;
let maxLen = 1;
let currentLen = 1;
for (let i = 1; i < arr.length; i++) {
if (arr[i] > arr[i - 1]) {
currentLen++;
maxLen = Math.max(maxLen, currentLen);
} else {
currentLen = 1;
}
}
return maxLen;
};
32. 最长递增子序列
给你一个整数数组
nums
,找到其中最长严格递增子序列的长度。初始化一个数组 dp 与输入数组 nums 长度相同,每个元素的值为 1。
第一层遍历所有;每个遍历它前面的值 只要有比当前值小的 看这个点的dep值+1 与当前的dep比较 哪个大取哪个
如果需要得到最长的子序列。可以把dep里存数组。比较的时候用长度P「初始值可以用map填进去当前数组」
var lengthOfLIS = function(nums) {
const dep = Array(nums.length).fill(1)
let result = 0
for(let i=0;i<nums.length;i++){
for(let j=0;j<i;j++){
if(nums[i]>nums[j]){
// 可以不连续 上升就可以
dep[i] = Math.max(dep[i],dep[j]+1)
}
}
result = Math.max(result,dep[i])
}
return result;
};
93.最长重复子数组
给两个整数数组 A
和 B
,返回两个数组中公共的、长度最长的子数组的长度。
示例:
输入: A: [1,2,3,2,1] B: [3,2,1,4,7] 输出:3 解释: 长度最长的公共子数组是 [3, 2, 1] 。
function findLength(nums1, nums2) {
let m = nums1.length, n = nums2.length;
//用一个二维数组 记录前面的相等次数。取最大值
let dp = Array.from({ length: m + 1 }, () => Array(n + 1).fill(0));
let maxLength = 0;
for (let i = 1; i <= m; i++) {
for (let j = 1; j <= n; j++) {
if (nums1[i - 1] === nums2[j - 1]) {
// 主要看前一个。当前值相等 前一个的值+1为现在的值
dp[i][j] = dp[i - 1][j - 1] + 1;
maxLength = Math.max(maxLength, dp[i][j]);
} else {
dp[i][j] = 0;
}
}
}
return maxLength;
}
34. 打乱数组
/**
* @param {number[]} nums
*/
var Solution = function(nums) {
this.original = nums.slice(); // 保存原始数组的副本
this.array = nums;
};
/**
* Resets the array to its original configuration and return it.
* @return {number[]}
*/
Solution.prototype.reset = function() {
this.array = this.original.slice(); // 恢复原始数组的副本
return this.array;
};
/**
* Returns a random shuffling of the array.
* @return {number[]}
*/
Solution.prototype.shuffle = function() {
for (let i = 0; i < this.array.length; i++) {
let rand = Math.floor(Math.random() * (i + 1)); // 随机选择一个小于或等于 i 的索引
// 交换当前元素和随机选择的元素
[this.array[i], this.array[rand]] = [this.array[rand], this.array[i]];
}
return this.array;
};
76.调整数组顺序使奇数位于偶数前面
var exchange = function(nums) {
let rt = []
for(let i=0,len=nums.length;i<len;i++){
if(nums[i]%2 ==0){
rt.push(nums[i])
}else{
rt.unshift(nums[i])
}
}
return rt;
};
let rt = exchange([1,2,3,4])
console.log(rt)
85.删除有序数组中的重复项
var removeDuplicates = function(nums) {
if (nums.length == 0) return 0;
let i = 0;
for (let j = 1; j < nums.length; j++) {
// 如果下一个和当前的相等就直接跳过 不想等时候 把不相等的移动到 前面来覆盖掉想等的值
if (nums[j] != nums[i]) {
i++;
// 不相等时候直接下一个赋值到当前值
nums[i] = nums[j];
}
}
return i + 1;
};
// 使用了splice截取数组
var removeDuplicates = function(nums) {
let len = nums.length
for(let i=0;i<len;i++){
if(nums[i] == nums[i-1]){
nums.splice(i,1)
len--
i--
}
}
return len
};
86.两个数组的交集
题:给定两个数组 nums1
和 nums2
,返回 它们的交集 。输出结果中的每个元素一定是 唯一 的。我们可以 不考虑输出结果的顺序 。
let rtArr =[]
while (arr1.length) {
let item = arr1.pop()
let index = arr2.indexOf (item)
if (index != -1&&!rtArr.includes(item)) {
// 确保重复的不被漏掉
arr2.splice(index, 1)
rtArr.push(item)
}
}
return rtArr