LeetCode经典题分类(数学 - 数组 - 字符串)精选 - JavaScript - ES6 - 技巧总结
Posted YK菌
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了LeetCode经典题分类(数学 - 数组 - 字符串)精选 - JavaScript - ES6 - 技巧总结相关的知识,希望对你有一定的参考价值。
文章目录
序号为LeetCode的题序,语言选择的是javascript
数字类
7. 整数反转
https://leetcode-cn.com/problems/reverse-integer/
给你一个 32 位的有符号整数 x ,返回将 x 中的数字部分反转后的结果。
【技巧】~~
取整(舍去小数位)
~
按位取反
对于整数相当于取反减一
~0 === -1
~1 === -2
~-1 === 0
~-2 === 1
对于小数相当于舍去小数位再取反减一
~0.3 === -1
~1.7 === -2
~-0.3 === -1
~-1.2 === 0
~-2.9 === 1
~~
按位取反再取反
对于整数还是自身
~~1 === 1
~~-1 === -1
~~0 === 0
对于小数,等于舍去小数位
相当于正数向下取整,负数向上取整
~~1.1 === 1
~~1.9 === 1
~~-1.1 === -1
~~-1.9 === -1
【技巧】Math.floor()
向下取整
Math.floor()
是向下取整
Math.floor(1.1) === 1
Math.floor(1.9) === 1
Math.floor(-1.1) === -2
Math.floor(-1.9) === -2
【解法】商与余数
整数除以10 余数为其个位数 商为去除个位数的剩余数字
整体思路就是遍历(x / 10
商)数字x
,每次拿数字的个位(x % 10
余数),直到拿完。
每次遍历都将x
的个位 拼接到result
的新腾出的个位上(result = result * 10 + (x % 10);
)
/**
* @param {number} x
* @return {number}
*/
var reverse = function (x) {
let result = 0;
while (x) {
result = result * 10 + (x % 10);
if (result > 2 ** 31 - 1 || result < -(2 ** 31)) return 0;
x = ~~(x / 10);
}
return result;
};
13. 罗马数字转整数
https://leetcode-cn.com/problems/roman-to-integer/
【解法一】Map
- 创建map映射
- 遍历字符串,在map中根据key取value (
map.get(s[i])
)
正常情况下 小的数在大的数的右边 直接累加
要先排除特殊情况 小的数在大的数的左边,那就给它前面加一个负号
/**
* @param {string} s
* @return {number}
*/
var romanToInt = function (s) {
let map = new Map();
map
.set("I", 1)
.set("V", 5)
.set("X", 10)
.set("L", 50)
.set("C", 100)
.set("D", 500)
.set("M", 1000);
let result = 0;
for (let i = 0; i < s.length; i++) {
let value = map.get(s[i]);
if (i < s.length - 1 && value < map.get(s[i + 1])) {
result -= value;
} else {
result += value;
}
}
return result;
};
【解法二】switch
【技巧】巧用switch
语句
有限种确定情况,完全可以用switch
语句
/**
* @param {string} s
* @return {number}
*/
var romanToInt = function (s) {
let result = 0;
for (let i = 0; i < s.length; i++) {
let value = getValue(s[i]);
if (i < s.length - 1 && value < getValue(s[i + 1])) {
result -= value;
} else {
result += value;
}
}
return result;
};
function getValue(s) {
switch (s) {
case "I":
return 1;
case "V":
return 5;
case "X":
return 10;
case "L":
return 50;
case "C":
return 100;
case "D":
return 500;
case "M":
return 1000;
default:
return 0;
}
}
数组类
1. 两数之和
https://leetcode-cn.com/problems/two-sum/
给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那 两个 整数,并返回它们的数组下标。
你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。
你可以按任意顺序返回答案。
【解法一】两层循环 - 暴力查找
i
遍历一遍数组;
j
从i+1
开始遍历剩余部分,看是否能找到等于 target-nums[i]
的元素, 找到返回下标
/**
* @param {number[]} nums
* @param {number} target
* @return {number[]}
*/
var twoSum = function (nums, target) {
for (let i = 0; i < nums.length; i++) {
for (let j = i + 1; j < nums.length; j++) {
if (nums[j] === target - nums[i]) {
return [i, j];
}
}
}
return [];
};
【解法二】一层循环 - Map
复习一下ES6的Map
【技巧】map
map会维护插入时的顺序
// 定义空map
let map = new Map();
// 添加元素
map.set("key1","value1").set("key2", "value2")
// 查询元素
map.has("key1") // true
map.get("key1") // "value1"
map.size === 2
构建映射【值:下标】
遍历nums构建map,之后只需在map中查找元素,而不需要每次都遍历剩余数组了
/**
* @param {number[]} nums
* @param {number} target
* @return {number[]}
*/
var twoSum = function(nums, target) {
let map = new Map();
for(let i = 0; i < nums.length; i++){
if(map.has(target-nums[i])){
return [map.get(target-nums[i]), i]
}
map.set(nums[i], i)
}
return []
};
【坑】注意题目条件 不可以取两次自己的下标
注意这里有一个坑,往map中存数据(set)操作要在判断语句之后!
因为不可以重复取两次自己,所以要在之前存入的元素中查找!!!
11. 盛最多水的容器
对撞指针
/**
* @param {number[]} height
* @return {number}
*/
var maxArea = function(height) {
let i = 0;
let j = height.length - 1;
let maxA = 0;
while(i<j){
let nowA = Math.min(height[i],height[j]) * (j - i);
maxA = Math.max(maxA, nowA)
if(height[i] <= height[j]){
i++;
}else{
j--;
}
}
return maxA;
};
26. 删除有序数组中的重复项
https://leetcode-cn.com/problems/remove-duplicates-from-sorted-array/
给你一个有序数组 nums ,请你 原地 删除重复出现的元素,使每个元素 只出现一次 ,返回删除后数组的新长度。
不要使用额外的数组空间,你必须在 原地 修改输入数组 并在使用 O(1) 额外空间的条件下完成。
【解法】快慢指针
快指针表示遍历数组到达的下标位置【遍历数组】
慢指针表示下一个不同元素要填入的下标位置【维持条件】
快指针 i
用来遍历一遍数组
慢指针 j
用来维护数组
注意这里的判断条件,满足条件【元素不重复】,慢指针j
才走
/**
* @param {number[]} nums
* @return {number}
*/
var removeDuplicates = function(nums) {
let j = 0
for(let i = 0; i < nums.length - 1; i++){
if(nums[i] !== nums[i+1]){
j++;
nums[j] = nums[i+1];
}
}
return j + 1;
};
27. 移除元素
https://leetcode-cn.com/problems/remove-element/
给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度。
不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并 原地 修改输入数组。
元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。
【解法】快慢指针
/**
* @param {number[]} nums
* @param {number} val
* @return {number}
*/
var removeElement = function(nums, val) {
let j = 0;
for(let i = 0; i< nums.length; i++){
if(nums[i] !== val){
nums[j] = nums[i];
j++;
}
}
return j;
};
53. 最大子序和
https://leetcode-cn.com/problems/maximum-subarray/
给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。
【解法】动态规划
thisSum
维护一个 向右累加 子序和 如果之前和子序和都没有第i个元素大,就从i开始重新维护一个 累加子序和
maxSum
保存遍历过程中的最大子序和
/**
* @param {number[]} nums
* @return {number}
*/
var maxSubArray = function(nums) {
let thisSum = 0
let maxSum = nums[0]
for(let i = 0; i<nums.length; i++){
if(thisSum + nums[i] < nums[i]){
thisSum = nums[i]
}else{
thisSum += nums[i]
}
if(thisSum > maxSum){
maxSum = thisSum
}
}
return maxSum
};
精简一下代码
/**
* @param {number[]} nums
* @return {number}
*/
var maxSubArray = function(nums) {
let thisSum = 0
let maxSum = nums[0]
for(let i = 0; i< nums.length; i++){
thisSum = Math.max(thisSum + nums[i], nums[i]);
maxSum = Math.max(maxSum, thisSum);
}
return maxSum;
};
75. 颜色分类
https://leetcode-cn.com/problems/sort-colors
给定一个包含红色、白色和蓝色,一共 n 个元素的数组,原地对它们进行排序,使得相同颜色的元素相邻,并按照红色、白色、蓝色顺序排列。
此题中,我们使用整数 0、 1 和 2 分别表示红色、白色和蓝色。
【解法一】两次遍历
一种很朴素的解法遍历两边,正着找0放在最前面,倒着找2放在最后面【双指针】
/**
* @param {number[]} nums
* @return {void} Do not return anything, modify nums in-place instead.
*/
var sortColors = function(nums) {
let first = 0;
let last = nums.length - 1;
for(let i = 0; i < nums.length; i++){
if(nums[i] === 0){
swap(nums, i, first);
first++;
}
}
for(let i = nums.length - 1; i >= 0; i--){
if(nums[i] === 2){
swap(nums, i, last);
last--;
}
}
};
function swap(nums,i,j){
let temp = nums[i];
nums[i] = nums[j];
nums[j] = temp;
}
也可以按顺序找,0放前面,1放中间,一样一样的【单指针】
var sortColors = function(nums) {
let first = 0
for(let i = 0; i < nums.length; i++){
if(nums[i] === 0){
swap(nums, i, first);
first++;
}
}
for(let i = first; i < nums.length; i++){
if(nums[i] === 1){
swap(nums, i, first);
first++;
}
}
};
【解法二】两层循环 冒泡排序
很多原地排序算法都可以【冒泡】【选择】【插入】等
更多关于排序算法可以参考这篇博文【算法】经典排序算法总结-JavaScript描述-图解-复杂度分析
var sortColors = function(nums) {
for (let i = 0; i < nums.length; i++) {
for (let j = 0; j < nums.length - i -1; j++) {
if (nums[j] > nums[j + 1]) {
swap(nums, j, j + 1);
}
}
}
};
【解法三】遍历一次 + 循环不变量【重点】
头尾指针i
和j
,遇到0
与nums[i]
交换,遇到2
与nums[j]
交换,遇到1
就跳过啥也不做
定义循环不变量
[0, i) === 0
(i, k) === 1
(j, nums.length-1] === 2
终止条件是k===j
var sortColors = function(nums) {
let i = 0;
let j = nums.length - 1;
for(let k = 0; k <= j; k++){
if(nums[k] === 0){
swap(nums, k, i);
i++;
}else if(nums[k] === 2){
swap(nums, k, j);
j--;
k--;
}
}
};
80. 删除有序数组中的重复项 II
https://leetcode-cn.com/problems/remove-duplicates-from-sorted-array-ii
给你一个有序数组 nums ,请你 原地 删除重复出现的元素,使每个元素 最多出现两次 ,返回删除后数组的新长度。
不要使用额外的数组空间,你必须在 原地 修改输入数组 并在使用 O(1) 额外空间的条件下完成。
【解法】快慢指针
/**
* @param {number[]} nums
* @return {number}
*/
var LeetCode经典题分类(链表 - 树 - 图)精选 - JavaScript - ES6 - 技巧总结
一文通数据结构与算法之——数组+常见题型与解题策略+Leetcode经典题