一. 数组
1.【2022.07.24】【1480】一维数组的动态和
🌟 LeetCode链接:链接
🌟 难度: 简单
给你一个数组 nums 。数组「动态和」的计算公式为:runningSum[i] = sum(nums[0]…nums[i]) 。
请返回 nums 的动态和。
- 示例 1
输入: nums = [1,2,3,4]
输出: [1,3,6,10]
解释: 动态和计算过程为 [1, 1+2, 1+2+3, 1+2+3+4] 。
- 示例 2
输入:nums = [1,1,1,1,1]
输出:[1,2,3,4,5]
解释:动态和计算过程为 [1, 1+1, 1+1+1, 1+1+1+1, 1+1+1+1+1] 。
🌟代码
var runningSum = function(nums) {
for (let i = 1; i < nums.length; i++) {
nums[i] += nums[i-1];
}
return nums;
};
2.【2022.07.25】【724】寻找数组的中心下标
🌟 LeetCode链接:链接
🌟 难度: 简单
给你一个整数数组 nums ,请计算数组的 中心下标 。
数组 中心下标 是数组的一个下标,其左侧所有元素相加的和等于右侧所有元素相加的和。
如果中心下标位于数组最左端,那么左侧数之和视为 0 ,因为在下标的左侧不存在元素。这一点对于中心下标位于数组最右端同样适用。
如果数组有多个中心下标,应该返回 最靠近左边 的那一个。如果数组不存在中心下标,返回 -1 。
🌟代码
/**
* @param {number[]} nums
* @return {number}
*/
var pivotIndex = function(nums) {
const total = nums.reduce((a, b) => a + b, 0);
let sum = 0;
for (let i = 0; i < nums.length; i++) {
if (2 * sum + nums[i] === total) {
return i;
}
sum += nums[i];
}
return -1;
}
3.【2022.08.01】【704】二分查找
🌟 LeetCode链接: 链接
🌟 难度: 简单
给定一个 n 个元素有序的(升序)整型数组
nums和一个目标值target,写一个函数搜索nums中的target,如果目标值存在返回下标,否则返回 -1。
- 示例 1
输入: nums = [-1,0,3,5,9,12], target = 9
输出: 4
解释: 9 出现在 nums 中并且下标为 4
- 示例 2
输入: nums = [-1,0,3,5,9,12], target = 2
输出: -1
解释: 2 不存在 nums 中因此返回 -1
🌟代码
/**
* @param {number[]} nums
* @param {number} target
* @return {number}
*/
var search = function(nums, target) {
let left = 0, right = nums.length -1;
while(left <= right) {
// 使用 Math.floor((high - low) / 2) + low 的原因:如果high特别大,但是没有越界,low特别大,但也没有越界,但是你把他俩相加就有可能越界,所以用low + (high - low) / 2 的方法来保证不会越界。low不越界,high-low肯定也不会越界。
const mid = Math.floor((high - low) / 2) + low;
const num = nums[mid];
if(num === target) {
return mid;
} else if(num < target) {
left = mid + 1;
} else {
right = mid - 1;
}
}
return -1;
}
4.【2022.08.01】【278】第一个错误的版本
🌟 LeetCode链接: 链接
🌟 难度: 简单
你是产品经理,目前正在带领一个团队开发新的产品。不幸的是,你的产品的最新版本没有通过质量检测。由于每个版本都是基于之前的版本开发的,所以错误的版本之后的所有版本都是错的。
假设你有 n 个版本
[1, 2, ..., n],你想找出导致之后所有版本出错的第一个错误的版本。你可以通过调用
bool isBadVersion(version)接口来判断版本号version是否在单元测试中出错。实现一个函数来查找第一个错误的版本。你应该尽量减少对调用API的次数。
- 示例 1
输入:n = 5, bad = 4
输出:4
解释:
调用 isBadVersion(3) -> false
调用 isBadVersion(5) -> true
调用 isBadVersion(4) -> true
所以,4 是第一个错误的版本。
- 示例 2
输入: n = 1, bad = 1
输出: 1
🌟代码
/**
* Definition for isBadVersion()
*
* @param {integer} version number
* @return {boolean} whether the version is bad
* isBadVersion = function(version) {
* ...
* };
*/
/**
* @param {function} isBadVersion()
* @return {function}
*/
var solution = function(isBadVersion) {
/**
* @param {integer} n Total versions
* @return {integer} The first bad version
*/
return function(n) {
let left = 1, right = n;
while(left < right) {
const mid = Math.floor((right - left) / 2) + left;
if(isBadVersion(n)) {
right = mid;
} else {
left = mid - 1;
}
}
return left;
}
}
5.【2022.08.02】【26】删除有序数组中的重复项
🌟 LeetCode链接: 链接
🌟 难度: 简单
给你一个
升序排列的数组nums,请你原地删除重复出现的元素,使每个元素只出现一次,返回删除后数组的新长度。元素的相对顺序应该保持 一致 。由于在某些语言中不能改变数组的长度,所以必须将结果放在数组nums的第一部分。更规范地说,如果在删除重复项之后有
k个元素,那么nums的前k个元素应该保存最终结果。将最终结果插入
nums的前k个位置后返回k。不要使用额外的空间,你必须在 原地 修改输入数组 并在使用 O(1) 额外空间的条件下完成。
输入:nums = [1,1,2]
输出:2, nums = [1,2,_]
解释:函数应该返回新的长度 2 ,并且原数组 nums 的前两个元素被修改为 1, 2 。不需要考虑数组中超出新长度后面的元素。
- 示例 2
输入:nums = [0,0,1,1,1,2,2,3,3,4]
输出:5, nums = [0,1,2,3,4]
解释:函数应该返回新的长度 5 , 并且原数组 nums 的前五个元素被修改为 0, 1, 2, 3, 4 。不需要考虑数组中超出新长度后面的元素。
🌟代码
/**
* @param {number[]} nums
* @return {number}
*/
var removeDuplicates = function(nums) {
const n = nums.length;
// 定义两个指针fast和slow分别为快指针和慢指针
// 快指针表示遍历数组到达的下标位置
// 慢指针表示下一个不同元素要填入的下标位置
// 初始时两个指针都指向下标1
let slow = 1, fast = 1;
while(fast < n) {
if(nums[fast] !== nums[fast - 1]) {
nums[slow] = nums[fast];
++slow;
}
++fast;
}
return slow;
}
6.【2022.08.02】【27】移除元素
🌟 LeetCode链接: 链接
🌟 难度: 简单
给你一个数组
nums和一个值val,你需要 原地 移除所有数值等于val的元素,并返回移除后数组的新长度。不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并 原地 修改输入数组。
元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。
- 示例 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],也会被视作正确答案。
- 示例 2
输入:nums = [0,1,2,2,3,0,4,2], val = 2
输出:5, nums = [0,1,4,0,3]
解释:函数应该返回新的长度 5, 并且 nums 中的前五个元素为 0, 1, 3, 0, 4。注意这五个元素可为任意顺序。你不需要考虑数组中超出新长度后面的元素。
🌟代码
/**
* @param {number[]} nums
* @return {number}
*/
var removeElement = function(nums, val) {
const n = nums.length;
let left = 0;
for(let right = 0; right < n; right++) {
if(nums[right] !== val) {
nums[left] = nums[right];
left++;
}
}
return left;
}
7.【2022.08.03】【88】合并两个有序数组
🌟 LeetCode链接: 链接
🌟 难度: 简单
给你两个按
非递减顺序排列的整数数组nums1和nums2,另有两个整数m和n,分别表示nums1和nums2中的元素数目。请你
合并nums2 到 nums1 中,使合并后的数组同样按非递减顺序排列。注意:最终,合并后数组不应由函数返回,而是存储在数组 nums1 中。为了应对这种情况,nums1 的初始长度为 m + n,其中前 m 个元素表示应合并的元素,后 n 个元素为 0 ,应忽略。nums2 的长度为 n 。
- 示例 1
输入:nums1 = [1,2,3,0,0,0], m = 3, nums2 = [2,5,6], n = 3
输出:[1,2,2,3,5,6]
解释:需要合并 [1,2,3] 和 [2,5,6] 。
合并结果是 [1,2,2,3,5,6] ,其中斜体加粗标注的为 nums1 中的元素。
- 示例 2
输入: nums1 = [1], m = 1, nums2 = [], n = 0
输出: [1]
解释: 需要合并 [1] 和 [] 。
合并结果是 [1] 。
- 示例 3
输入:nums1 = [0], m = 0, nums2 = [1], n = 1
输出:[1]
解释:需要合并的数组是 [] 和 [1] 。
合并结果是 [1] 。
注意,因为 m = 0 ,所以 nums1 中没有元素。nums1 中仅存的 0 仅仅是为了确保合并结果可以顺利存放到 nums1 中。
🌟代码
/**
* @param {number[]} nums1
* @param {number} m
* @param {number[]} nums2
* @param {number} n
* @return {void} Do not return anything, modify nums1 in-place instead.
*/
var merge = function(nums1, m, nums2, n) {
nums1.splice(m, nums1.lenth - 3, ...nums2);
nums1.sort((a, b) => a - b);
}
8.【2022.08.03】【35】搜索插入位置
🌟 LeetCode链接: 链接
🌟 难度: 简单
给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。
请必须使用时间复杂度为
O(log n)的算法。
- 示例 1
输入: nums = [1,3,5,6], target = 5
输出: 2
- 示例 2
输入: nums = [1,3,5,6], target = 2
输出: 1
- 示例 3
输入: nums = [1,3,5,6], target = 7
输出: 4
🌟代码
/**
* @param {number[]} nums
* @param {number} target
* @return {number}
*/
var searchInsert = function(nums, target) {
const n = nums.length;
let left = 0, right = n - 1, ans = n;
while (left <= right) {
let mid = Math.floor((right - left) / 2) + left;
if (target <= nums[mid]) {
ans = mid;
right = mid - 1;
} else {
left = mid + 1;
}
}
return ans;
};
9.【2022.08.15】【66】加一
🌟 LeetCode链接: 链接
🌟 难度: 简单
给定一个由 整数 组成的 非空 数组所表示的非负整数,在该数的基础上加一。
最高位数字存放在数组的首位, 数组中每个元素只存储单个数字。
你可以假设除了整数 0 之外,这个整数不会以零开头。
- 示例 1
输入: digits = [4,3,2,1]
输出: [4,3,2,2]
解释: 输入数组表示数字 4321。
- 示例 2
输入: digits = [1,2,3]
输出: [1,2,4]
解释: 输入数组表示数字 123。
- 示例 3
输入: digits = [0]
输出: [1]
🌟代码
/**
* @param {number[]} digits
* @return {number[]}
*/
var plusOne = function(digits) {
const n = digits.length;
for (let i = n - 1; i >= 0; --i) {
if (digits[i] !== 9) {
++digits[i];
for (let j = i + 1; j < n; ++j) {
digits[j] = 0;
}
return digits;
}
}
// digits 中所有的元素均为 9
const ans = new Array(n + 1).fill(0);
ans[0] = 1;
return ans;
};
10.【2022.08.16】【136】只出现一次的数字
🌟 LeetCode链接: 链接
🌟 难度: 简单
给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。
说明:
你的算法应该具有线性时间复杂度。 你可以不使用额外空间来实现吗?
- 示例 1
输入: [2,2,1]
输出: 1
- 示例 2
输入: [4,1,2,1,2]
输出: 4
🌟代码
/**
* @param {number[]} nums
* @return {number}
*/
var singleNumber = function(nums) {
let ans = 0;
for(const num of nums) {
ans ^= num;
}
return ans;
};
11.【2022.08.17】【169】多数元素
🌟 LeetCode链接: 链接
🌟 难度: 简单
给定一个大小为 n 的数组 nums ,返回其中的多数元素。多数元素是指在数组中出现次数 大于 ⌊ n/2 ⌋ 的元素。
你可以假设数组是非空的,并且给定的数组总是存在多数元素。
- 示例 1
输入: nums = [3,2,3]
输出: 3
- 示例 2
输入: nums = [2,2,1,1,1,2,2]
输出: 2
🌟代码
/**
* @param {number[]} nums
* @return {number}
*/
// 思路:排序数组,如果有一个数字出现的频率大于n/2,则在数组中nums.length/2的位置就是这个数
var majorityElement = function(nums) {
// 排序
nums.sort((a, b) => a - b);
return nums[Math.floor(nums.length / 2)];
};
二. 递归
fn(0);
function fn(nub){
if(nub < 5){
fn(nub+1);
}
console.log(nub);
}
// 5 4 3 2 1 0
1.【2022.07.26】【21】合并两个有序链表
🌟 LeetCode链接: 链接
🌟 难度: 简单
将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。
- 示例 1
输入: l1 = [1,2,4], l2 = [1,3,4]
输出: [1,1,2,3,4,4]
- 示例 2
输入: l1 = [], l2 = []
输出: []
- 示例 3
输入: l1 = [], l2 = [0]
输出: [0]
🌟代码
/**
* Definition for singly-linked list.
* function ListNode(val, next) {
* this.val = (val===undefined ? 0 : val)
* this.next = (next===undefined ? null : next)
* }
*/
/**
* @param {ListNode} list1
* @param {ListNode} list2
* @return {ListNode}
*/
var mergeTwoLists = function(list1, list2) {
if (list1 === null) {
return list2;
} else if (list2 === null) {
return list1;
} else if(list1.val < list2.val) {
list1.next = mergeTwoLists(list1.next, list2);
return list1;
} else {
list2.next = mergeTwoLists(list1, list2.next);
return list2;
}
};
2.【2022.07.27】【206】反转链表
🌟 LeetCode链接: 链接
🌟 难度: 简单
给你单链表的头节点
head,请你反转链表,并返回反转后的链表。
- 示例 1
输入: head = [1,2,3,4,5]
输出: [5,4,3,2,1]
- 示例 2
输入: head = [1,2]
输出: [2,1]
- 示例 3
输入: head = []
输出: []
🌟代码
/** * Definition for singly-linked list.
* function ListNode(val, next) {
* this.val = (val===undefined ? 0 : val)
* this.next = (next===undefined ? null : next)
* }
*/
/**
* @param {ListNode} head
* @return {ListNode}
*/
// 方法一 迭代
var reverseList = function(head) {
let prev = null; let curr = head;
while(curr) {
const next = curr.next;
curr.next = prev;
prev = curr;
curr = next;
}
return prev;
};
// 方法二 递归
var reverseList = function(head) {
if (head == null || head.next == null) {
return head;
}
const newHead = reverseList(head.next);
head.next.next = head;
head.next = null;
return newHead;
};
三. 字符串
1.【2022.07.28】【205】同构字符串
🌟 LeetCode链接: 链接
🌟 难度: 简单
给定两个字符串 s 和 t ,判断它们是否是同构的。
如果 s 中的字符可以按某种映射关系替换得到 t ,那么这两个字符串是同构的。
每个出现的字符都应当映射到另一个字符,同时不改变字符的顺序。不同字符不能映射到同一个字符上,相同字符只能映射到同一个字符上,字符可以映射到自己本身。
- 示例 1
输入: s = "egg", t = "add"
输出: true
- 示例 2
输入: s = "foo", t = "bar"
输出: false
- 示例 3
输入: s = "paper", t = "title"
输出: true
/**
* @param {string} s
* @param {string} t
* @return {boolean}
*/
var isIsomorphic = function(s, t) {
const s2t = {};
const t2s = {};
const len = s.length;
for(let i = 0; i < len; i++) {
const x = s[i], y = t[i];
if((s2t[x] && s2t[x] !== y) || (t2s[y] && t2s[y] !== x)) {
return false;
}
s2t[x] = y;
t2s[y] = x;
}
return true;
}
2.【2022.07.29】【392】判断子序列
🌟 LeetCode链接: 链接
🌟 难度: 简单
给定字符串 s 和 t ,判断 s 是否为 t 的子序列。
字符串的一个子序列是原始字符串删除一些(也可以不删除)字符而不改变剩余字符相对位置形成的新字符串。(例如,"ace"是"abcde"的一个子序列,而"aec"不是)。
- 示例 1
输入: s = "abc", t = "ahbgdc"
输出: true
/**
* @param {string} s
* @param {string} t
* @return {boolean}
*/
var isSubsequence = function(s, t) {
};