前言
大概从三月初开始,踏入了力扣刷题的队伍。每天一道算法题准备春招,算下来好像也就二三十道(好少啊,突然觉得刷几百题的人太牛逼了)。过了一个月感觉大部分都忘了,就对自己以前刷过的题大概进行下总结
1. 303.区域和检索-数组不可变
1.1 题目描述
原题链接:leetcode-cn.com/problems/ra…
给定一个整数数组 nums,求出数组从索引 i 到 j(i ≤ j)范围内元素的总和,包含 i、j 两点。
实现 NumArray 类:
NumArray(int[] nums) 使用数组 nums 初始化对象
int sumRange(int i, int j) 返回数组 nums 从索引 i 到 j(i ≤ j)范围内元素的总和,包含 i、j 两点(也就是 sum(nums[i], nums[i + 1], ... , nums[j]))
示例:
输入:
["NumArray", "sumRange", "sumRange", "sumRange"]
[[[-2, 0, 3, -5, 2, -1]], [0, 2], [2, 5], [0, 5]]
输出:
[null, 1, -1, -3]
解释:
NumArray numArray = new NumArray([-2, 0, 3, -5, 2, -1]);
numArray.sumRange(0, 2); // return 1 ((-2) + 0 + 3)
numArray.sumRange(2, 5); // return -1 (3 + (-5) + 2 + (-1))
numArray.sumRange(0, 5); // return -3 ((-2) + 0 + 3 + (-5) + 2 + (-1))
1.2 思路分析
这个题目要计算第i个值到第j个值的总和。那我们可以先计算前n个数值的和的值,将值存到某个数组中(数组开头为0,这样方便计算第j个数到第0个数的值),计算i到j值总和时,直接相减就可以。比如:
sum=[0,0,0,0,0]
nums=[1,2,3,4]
sum[1]存储第1个数值之和 ,下标为0到0数值之和:
sum[1] = sum[0] + nums[0] = 1
sum[2]存储第1个到第2个数值之和 , 下标为0到1数值之和:
sum[2] = sum[1] + nums[1] = sum[0] + nums[0] + nums[1] = 0+1+2 = 3
sum[3]存储第1个到第3个数值之和 , 下标为0到2数值之和:
sum[3] = sum[2] + nums[2] = sum[0] + nums[0] + nums[1] + nums[2]= 0+1+2+3 = 6
····
取num下标为1到2的值
sum[3] - sum [1]
=( sum[0] + nums[0] + nums[1] + nums[2] ) - ( sum[0] + nums[0] )
=nums[1] + nums[2]
=6-1=5
1.3 代码
var NumArray = function(nums) {
var a=nums.length
sums = new Array(a+1).fill(0)
for(let i=0;i<a;i++){
sums[i+1]=sums[i]+nums[i]
}
console.log(sums)
};
NumArray.prototype.sumRange = function(i, j) {
return sums[j+1]-sums[i]
};
2. 304.二维矩阵和检索-矩阵不可变
2.1 题目描述
原题链接:leetcode-cn.com/problems/ra…
给定一个二维矩阵,计算其子矩形范围内元素的总和,该子矩阵的左上角为 (row1, col1) ,
右下角为 (row2, col2) 。
上图子矩阵左上角 (row1, col1) = (2, 1) ,右下角(row2, col2) = (4, 3),该子矩形内元素的总和为 8。
示例:
给定 matrix = [ [3, 0, 1, 4, 2],
[5, 6, 3, 2, 1],
[1, 2, 0, 1, 5],
[4, 1, 0, 1, 7],
[1, 0, 3, 0, 5]
]
sumRegion(2, 1, 4, 3) -> 8
sumRegion(1, 1, 2, 2) -> 11
sumRegion(1, 2, 2, 4) -> 12
2.2 思路分析
该题想计算子矩形内元素总和,可跟上题解决方法一样,就是计算多行i到j的值相加,新建一个数组,存储对矩阵前缀相加之和,然后对每一行的子数组和计算总和。例如:
0 1 2 0 0 1 3
3 4 5 ====> 0 3 7 12
3 4 2 0 3 7 9
2.3 代码
var NumMatrix = function(matrix) {
var i=matrix.length
if(i>0){
var j=matrix[0].length
// sum =new Array[i,j+1]
sum = new Array(i).fill(0).map(() => new Array(j + 1).fill(0));
for (let a=0;a<i;a++){
for(let b=0;b<j;b++){
sum[a][b+1]=sum[a][b]+matrix[a][b]
}
}
}
};
NumMatrix.prototype.sumRegion = function(row1, col1, row2, col2) {
let sums=0
for(row1;row1<=row2;row1++){
sums=sum[row1][col2+1]-sum[row1][col1]+sums
}
return sums
};
3. 338.比特位计数
3.1 题目描述
原题链接:leetcode-cn.com/problems/co…
给定一个非负整数 num。对于 0 ≤ i ≤ num 范围中的每个数字 i,
计算其二进制数中的 1 的数目并将它们作为数组返回。
示例 1:
输入: 2
输出: [0,1,1]
示例 2:
输入: 5
输出: [0,1,1,2,1,2]
3.2 思路分析
先用for循环遍历输出一遍,将每个数值转换成二进制,使用正则表达式计算搜索并返回数组,计算数组长度
3.3 代码
var countBits = function(num) {
a=new Array()
for(let i=0;i<=num;i++){
a.push((i.toString(2).match(/1/g) ||[]).length)
}
return a;
};
4. 354.俄罗斯套娃信封问题
4.1 题目描述
原题链接:leetcode-cn.com/problems/ru…
给你一个二维整数数组 envelopes ,其中 envelopes[i] = [wi, hi] ,表示第 i 个信封的宽度和高度。
当另一个信封的宽度和高度都比这个信封大的时候,这个信封就可以放进另一个信封里,如同俄罗斯套娃一样。
请计算 最多能有多少个 信封能组成一组“俄罗斯套娃”信封(即可以把一个信封放到另一个信封里面)。
注意:不允许旋转信封。
示例 1:
输入:envelopes = [[5,4],[6,4],[6,7],[2,3]]
输出:3
解释:最多信封的个数为 3, 组合为: [2,3] => [5,4] => [6,7]。
示例 2:
输入:envelopes = [[1,1],[1,1],[1,1]]
输出:1
4.2 思路分析
我们可以将信封数组按照大小排序,按照长度从小向大排序,如果长度相等,则按照宽度从大到小排序。定义一个数组f,每个数组对应的值记录每个信封所能包含最大的信封个数,之后对遍历数组将其和以前的信封最大值进行比较,如果 i 宽度大于数组 j ( i之前的信封 ) 的宽度,表示能套进信封内,则将f[i]的值改变,i能套住j,表示i能套住j能套住所有信封的值,取最大值。
4.3 代码
var maxEnvelopes = function(envelopes) {
if (envelopes.length === 0) {
return 0;
}
const n = envelopes.length;
envelopes.sort((e1, e2) => {
if (e1[0] !== e2[0]) {
return e1[0] - e2[0];
} else {
return e2[1] - e1[1];
}
})
console.log(envelopes)
const f = new Array(n).fill(1);
let ans = 1;
for (let i = 1; i < n; ++i) {
for (let j = 0; j < i; ++j) {
if (envelopes[j][1] < envelopes[i][1]) {
f[i] = Math.max(f[i], f[j] + 1);
}
}
ans = Math.max(ans, f[i]);
}
return ans;
};
5. 503.下一个更大元素
5.1 题目描述
原题链接:leetcode-cn.com/problems/ne…
给定一个循环数组(最后一个元素的下一个元素是数组的第一个元素),
输出每个元素的下一个更大元素。数字 x 的下一个更大的元素是按数组遍历顺序,
这个数字之后的第一个比它更大的数,这意味着你应该循环地搜索它的下一个更大的数。
如果不存在,则输出 -1。
示例 1:
输入: [1,2,1]
输出: [2,-1,2]
解释: 第一个 1 的下一个更大的数是 2;
数字 2 找不到下一个更大的数;
第二个 1 的下一个最大的数需要循环搜索,结果也是 2。
5.2 思路分析
要对数组循环搜索最大值,我们可以直接将数组后面再增添一个原数值的数组 这样可以不用循环遍历数组,对其进行比较
5.3 代码
var nextGreaterElements = function(nums) {
let arr = nums.concat(nums);
return nums.map((item, id) => {
for(let i = id + 1; i < arr.length; i++){
if(item < arr[i]) return arr[i];
}
return -1;
})
};
6. 224. 基本计算器
6.1 题目描述
原题链接:leetcode-cn.com/problems/ba…
给你一个字符串表达式 s ,请你实现一个基本计算器来计算并返回它的值。
示例 1:
输入:s = "1 + 1"
输出:2
示例 2:
输入:s = " 2-1 + 2 "
输出:3
示例 3:
输入:s = "(1+(4+5+2)-3)+(6+8)"
输出:23
提示:
1 <= s.length <= 3 * 105
s 由数字、'+'、'-'、'('、')'、和 ' ' 组成
s 表示一个有效的表达式
6.2 思路分析
提示里表明s 由数字、'+'、'-'、'('、')'、和 ' ' 组成,如果是+,括号无作用则对原数值无改变,比如1+(1+2)=1+1+2。如果为-,则括号的作用就是符号反转, 比如1-(2-3)=1-2+3。则只需要定义一个sign表示符号变化,stack记录符号变化。
6.3 代码
var calculate = function(s) {
const stack = [1]
let sign = 1;
let sum =0
const n =s.length;
let i =0;
while( i < n){
if(s[i]===' '){
i++
}else if(s[i] === '+'){
sign = stack[stack.length-1]
i++
}else if(s[i] ==='-'){
sign = -stack[stack.length-1]
i++
}else if(s[i] ==='('){
stack.push(sign);
i++
}else if(s[i] ===')'){
stack.pop(sign)
i++
}else {
let num=0
while(i<n && !(isNaN(Number(s[i]))) && s[i] !==' '){
num = s[i].charCodeAt() - '0'.charCodeAt();
i++
}
sum+=sign*num
}
}
return sum
};
7. 227.基本计算器2
7.1 题目描述
原题链接:leetcode-cn.com/problems/ba…
给你一个字符串表达式 s ,请你实现一个基本计算器来计算并返回它的值。
整数除法仅保留整数部分。
示例 1:
输入:s = "3+2*2"
输出:7
示例 2:
输入:s = " 3/2 "
输出:1
示例 3:
输入:s = " 3+5 / 2 "
输出:5
提示:
1 <= s.length <= 3 * 105
s 由整数和算符 ('+', '-', '*', '/') 组成,中间由一些空格隔开
s 表示一个 有效表达式
表达式中的所有整数都是非负整数,且在范围 [0, 231 - 1] 内
题目数据保证答案是一个 32-bit 整数
7.2 思路分析
该题需要先进行乘除,后加减。我们可以定义一个栈如果为加减就先把该数值入栈,为乘除我们可以将进栈最后一个元素输出与其进行运算 ,将运算后的值存入栈。
7.3 代码
var calculate = function(s) {
//trim() 方法用于删除字符串的头尾空白符,
s = s.trim()
const stack = new Array()
let a = '+'
let num = 0
const n = s.length
for(let i =0 ; i<n ; i++){
if(!isNaN(Number(s[i])) && s[i]!==' '){
num =num*10+ s[i].charCodeAt() - '0'.charCodeAt()
}
if(isNaN(Number(s[i])) || i === n-1){
switch(a){
case '+':
stack.push(num)
break
case '-':
stack.push(-num);
break
case '*':
stack.push(stack.pop()*num)
break
case '/':
stack.push(stack.pop() / num | 0 )
break
}
a = s[i]
num = 0;
}
}
let ans = 0
while(stack.length){
ans +=stack.pop()
}
return ans;
};
8. 456.132模式
8.1 题目描述
原题链接:leetcode-cn.com/problems/13…
给你一个整数数组 nums ,数组中共有 n 个整数。132 模式的子序列 由三个整数 nums[i]
nums[j] 和 nums[k] 组成,并同时满足:i < j < k 和 nums[i] < nums[k] < nums[j] 。
如果 nums 中存在 132 模式的子序列 ,返回 true ;否则,返回 false 。
示例 1:
输入:nums = [1,2,3,4]
输出:false
解释:序列中不存在 132 模式的子序列。
示例 2:
输入:nums = [3,1,4,2]
输出:true
解释:序列中有 1 个 132 模式的子序列: [1, 4, 2] 。
示例 3:
输入:nums = [-1,3,2,0]
输出:true
解释:序列中有 3 个 132 模式的的子序列:[-1, 3, 2]、[-1, 3, 0] 和 [-1, 2, 0] 。
提示:
n == nums.length
1 <= n <= 104
-109 <= nums[i] <= 109
8.2 思路分析
我们可以从后往前寻找,假设最后一个数为a,往前寻找是否有比最后一个数值大的数b。如果有那么a为第二大的数,b为最大数,再往前寻找是否有比b还大的数值,如果有那b为第二大,把值赋给a,只要有个数小于a就为132模式。如果没有值大于a,则将其数值入栈(nums为...456模式),栈尾为最小值,再往前搜寻,如果大于栈尾的值,原理和1一样
8.3 代码
var find132pattern = function(nums) {
var len = nums.length
var max = -Number.MAX_SAFE_INTEGER
var stack =[nums[len-1]]
for(let i = len-2;i>=0;i--){
if(nums[i]<max){
return true
}
while(stack.length && nums[i] > stack[stack.length-1]){
max = stack[stack.length-1]
stack.pop()
}
if(nums[i]>max){
stack.push(nums[i])
}
}
return false
9. 扁平化嵌套列表迭代器
9.1 题目描述
原题链接:leetcode-cn.com/problems/fl…
给你一个嵌套的整型列表。请你设计一个迭代器,使其能够遍历这个整型列表中的所有整数。
列表中的每一项或者为一个整数,或者是另一个列表。其中列表的元素也可能是整数或是其他列表。
示例 1:
输入: [[1,1],2,[1,1]]
输出: [1,1,2,1,1]
解释: 通过重复调用 next 直到 hasNext 返回 false,next 返回的元素的顺序应该是: [1,1,2,1,1]。
示例 2:
输入: [1,[4,[6]]]
输出: [1,4,6]
解释: 通过重复调用 next 直到 hasNext 返回 false,next 返回的元素的顺序应该是: [1,4,6]。
9.2 思路分析
我们可以使用嵌套函数,遍历列表,如果列表中的数值为数字,建一个栈接收这个值,否则为列表,则其传给函数重新遍历
9.3 代码
var NestedIterator = function(nestedList) {
arrs =[];
const dfs = (nestedList) =>{
for(const nest of nestedList){
if(nest.isInteger()){
arrs.push(nest.getInteger())
}else{
dfs(nest.getList())
}
}
}
dfs(nestedList)
};
NestedIterator.prototype.hasNext = function() {
return arrs.length>0
};
NestedIterator.prototype.next = function() {
const arr= arrs[0];
// console.log(arrs,arr)
arrs = arrs.slice(1);
return arr;
};
10. 两数相加
10.1 题目描述
原题链接:leetcode-cn.com/problems/ad…
给你两个 非空 的链表,表示两个非负的整数。
它们每位数字都是按照 逆序 的方式存储的,并且每个节点只能存储 一位 数字。
请你将两个数相加,并以相同形式返回一个表示和的链表。
你可以假设除了数字 0 之外,这两个数都不会以 0 开头。
示例 1:
输入:l1 = [2,4,3], l2 = [5,6,4]
输出:[7,0,8]
解释:342 + 465 = 807.
示例 2:
输入:l1 = [0], l2 = [0]
输出:[0]
示例 3:
输入:l1 = [9,9,9,9,9,9,9], l2 = [9,9,9,9]
输出:[8,9,9,9,0,0,0,1]
来源:力扣(LeetCode)
链接:
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
10.2 思路分析
我们同时遍历两个链表,逐位计算它们的和,并与当前位置的进位值相加。具体而言,如果当前两个链表处相应位置的数字为 n1 、 n2进位值为carry,则它们的和为 n1+n2+carry。如果两个链表的长度不同,则可以认为长度短的链表的后面有若干个 00 。此外,如果链表遍历结束后,carry>0,还需要在答案链表的后面附加一个节点,节点的值为 carry。用head来记录加的数值。
10.3 代码
var addTwoNumbers = function(l1, l2) {
let head = null, tail = null;
let carry = 0;
while (l1 || l2) {
const n1 = l1 ? l1.val : 0;
//val() 方法返回或设置被选元素的值。
const n2 = l2 ? l2.val : 0;
const sum = n1 + n2 + carry;
if (!head) {
head = tail = new ListNode(sum % 10);
// console.log(head)
} else {
tail.next = new ListNode(sum % 10);
// console.log(tail,tail.next)
tail = tail.next;
}
// console.log(tail)
carry = Math.floor(sum / 10);
//floor() 方法可对一个数进行下舍入
if (l1) {
l1 = l1.next;
}
if (l2) {
l2 = l2.next;
}
}
if (carry > 0) {
tail.next = new ListNode(carry);
}
return head;
};
写不动了,下次再说......