leetcode hot100解题总结 JS(持续更新)
Posted 九是我呀
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了leetcode hot100解题总结 JS(持续更新)相关的知识,希望对你有一定的参考价值。
53. 最大子序和
给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。
示例 1:
输入:nums = [-2,1,-3,4,-1,2,1,-5,4]
输出:6
解释:连续子数组 [4,-1,2,1] 的和最大,为 6 。
/**
* @param {number[]} nums
* @return {number}
*/
var maxSubArray = function(nums) {
let res = nums[0], curSum = nums[0];
for(let i= 1; i< nums.length; i++){
curSum = Math.max(nums[i], curSum + nums[i])
res = Math.max(res, curSum)
}
return res
};
121. 买卖股票的最佳时机
给定一个数组 prices ,它的第 i 个元素 prices[i] 表示一支给定股票第 i 天的价格。
你只能选择 某一天 买入这只股票,并选择在 未来的某一个不同的日子 卖出该股票。设计一个算法来计算你所能获取的最大利润。
返回你可以从这笔交易中获取的最大利润。如果你不能获取任何利润,返回 0 。
思路:遍历一遍,将最小值记录下来,然后对比当前值和最小值的差值
/**
* @param {number[]} prices
* @return {number}
*/
var maxProfit = function(prices) {
let min = prices[0] //min为最小值
let res = 0 //res为差值
for(let i =1; i<prices.length; i++){
min = Math.min(min, prices[i]) //比较最小值和当前值,选最小
res = Math.max(res, prices[i]- min) // 比较最小差值和当前差值
}
return res
};
141. 环形链表
给定一个链表,判断链表中是否有环。
如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。注意:pos 不作为参数进行传递,仅仅是为了标识链表的实际情况。
如果链表中存在环,则返回 true 。 否则,返回 false 。
/**
* Definition for singly-linked list.
* function ListNode(val) {
* this.val = val;
* this.next = null;
* }
*/
/**
* @param {ListNode} head
* @return {boolean}
*/
var hasCycle = function(head) {
let p = q = head
if(p == null){ //判断头是否为空,不然后面q.next会执行出错
return false
}
while(q.next!=null && q.next.next !=null){
p = p.next;
q = q.next.next
if(q == p && q!=null && p !=null){
return true
}
}
return false
};
101对称二叉树
给定一个二叉树,检查它是否是镜像对称的。
分析:这道题难点在于递归,是我已知以来的难点,很多时候明明知道用递归,但还是会不知所措。
var isSymmetric = function(root) {
//判断根是否为空
if(root==null){
return true;
}
return isTrue(root.left, root.right);
};
//递归判断是否为对称,很容易想到,要判断左子树和右子树的值是否一致,
//若一致,再判断其左子树的左值和右子树的右值是否一致,以及左子树的右值和右子树的左值是否一致,
//其实这个过程是在判断相应的子树是否对称。终止条件就是若左右其中一个为空,则假,若左右均为空,则真。
function isTrue(leftTree, rightTree){
if(leftTree == null && rightTree ==null){
return true;
}
if((!leftTree && rightTree) || (leftTree && !rightTree)){
return false;
}
return (leftTree.val == rightTree.val&& isTrue(leftTree.right, rightTree.left) && isTrue(leftTree.left, rightTree.right))
}
21. 合并两个有序链表
将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。
/**
* Definition for singly-linked list.
* function ListNode(val, next) {
* this.val = (val===undefined ? 0 : val)
* this.next = (next===undefined ? null : next)
* }
*/
/**
* @param {ListNode} l1
* @param {ListNode} l2
* @return {ListNode}
*/
//难点:总是碰到指针问题就不知所措
//两个不同长度的链表,判断到最后,如果一个为空 ,则将另外一个正便利的节点附给那个节点的next就行
var mergeTwoLists = function(l1, l2) {
let p = l1;
let q = l2;
let head = new ListNode(-1);
let prev = head;
if(l1 == null){
return l2;
}else if(l2 ==null){
return l1;
}
while(l1 && l2){ //判断是否一方已遍历完成
if(l1.val <= l2.val){
prev.next = l1; //用的原来的节点而不是新创节点
l1 = l1.next;
}else if(l1.val >= l2.val){
prev.next = l2;
l2 = l2.next;
}
prev = prev.next;
}
prev.next = l1 == null ? l2 : l1; //如何让处理剩下的节点,像链表是连着的就可以直接确定一个就行,数组不同的地方就是需要一个个加进去
return head.next;
};
11. 盛最多水的容器
给你 n 个非负整数 a1,a2,...,an,每个数代表坐标中的一个点 (i, ai) 。在坐标内画 n 条垂直线,垂直线 i 的两个端点分别为 (i, ai) 和 (i, 0) 。找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。说明:你不能倾斜容器。
输入:[1,8,6,2,5,4,8,3,7]
输出:49
解释:图中垂直线代表输入数组 [1,8,6,2,5,4,8,3,7]。在此情况下,容器能够容纳水(表示为蓝色部分)的最大值为 49。
/**
* @param {number[]} height
* @return {number}
*/
//双指针方法
var maxArea = function(height) {
//解构语法进行赋值,若做指针值小于右指针,则计算体积,并将左指针右移,否则计算体积,并将左指针移动。为什么每次都将短的一方移动呢,因为V = 短板长度*t, t为两个值的间距,但是无论右指针左移还是左指针右移,下一个t为t-1,肯定会减小,所以我们只需关注新短板长度即可。如果移动长板的话,短板肯定不变或者较少,肯定不会变大。但是移动短板的话,可能会变大或者不变或者减少。
let [maxV, i, j] =[0, 0, height.length -1];
while(i < j){
if (height[i] <= height[j]){
maxV = Math.max(maxV , (j-i) * height[i]);
i++;
} else if(height[i] > height[j]){
maxV = Math.max(maxV , (j-i) * height[j]);
j--;
}
}
return maxV;
};
5. 最长回文子串(2021.7.25)
给你一个字符串 s,找到 s 中最长的回文子串。
// 方法一:暴力解决
// 遍历每个子串,看是否是回文串
/**
* @param {string} s
* @return {string}
*/
var longestPalindrome = function(s) {
let len = (s.length + 1) * s.length /2;
let max =0;
let map1 = new Map();
for(let i =0; i< s.length; i++){
for(let j =i; j<s.length;j++){
if(isTruth(s.slice(i,j+1))){
if(s.slice(i,j+1).length > max) {
map1.set(s.slice(i,j+1).length, s.slice(i,j+1));
max = s.slice(i,j+1).length;
}
}
}
}
return map1.get(max);
};
var isTruth = ( subStr) =>{
for(let i = 0; i< Math.ceil(subStr.length/2); i++){
if(subStr[i] != subStr[subStr.length - i -1]){
return 0;
}
}
return 1;
}
//中心扩展法
//思路:从左到右每次选一个数作为中心,向左右两边扩展,先找到相同的元素(先向右循环,直至不相等,再向左循环,直至不相等),然后再看左右两边的元素是否相等,如果相等,分别向左向右移动。不等则计算
var longestPalindrome = function(s){
let len;
let max = 0;
// 取最长长度时的maxStart,maxEnd,其实maxStart代表索引的前一位,maxEnd代表索引的后一位。
let maxStart = maxEnd = 0;
//遍历所有元素
for(let cur = 0; cur <s.length; cur++){
let right = left = cur;
//先向右循环,此时right指向不相等的那个元素,right最大值为s.length,即右索引的后一个
while(right <= s.length){
if(s[right] != s[cur] ){
break;
}
right ++;
}
//再向左循环,此时left指向不相等的那个元素,left最小为-1,即左索引的前一位
while(left>= 0){
if(s[left] != s[cur] ){
break;
}
left--;
}
//分别向左向右移动
while(left>= 0 && right <= s.length && s[right] == s[left]){
left--;
right++;
}
maxStart = len > max ? left : maxStart;
maxEnd = len > max ? right : maxEnd;
max = len > max ? len : max;
}
return s.slice(maxStart+1, maxEnd);
}
插播1(2021字节前端提前批,惨痛的教训)
415.给定两个字符串形式的非负整数 num1 和num2 ,计算它们的和。(2021.7.24)
/**
* @param {string} num1
* @param {string} num2
* @return {string}
*/
// 方法一
var addStrings = function(num1, num2) {
let res = \'\';
let len1 = num1.length;
let len2 = num2.length;
let i = 0, j = 0, temp = 0;
// 填充0
len1 < len2 ? num1 = num1.padStart(len2, \'0\') : num2 = num2.padStart(len1, \'0\');
let newLen = len1 > len2 ? len1 :len2;
for(let i = newLen - 1; i >= 0; i--){
let sum = parseInt(num1[i]) + parseInt(num2[i]) + temp;
temp = sum > 9 ? 1 : 0; //可优化为temp = Math.floor(sum / 10)
res = (sum > 9 ? sum % 10 : sum) + res; // res = sum % 10
}
if(temp === 1){
res = \'1\' + res;
}
return res;
};
//方法二: 上面占据了很多空间,可以进行判断.但这种虽然时间快,但占内存
//执行用时:92 ms , 在所有 javascript 提交中击败了 68.05%的用户
//内存消耗: 39.9 MB , 在所有 JavaScript 提交中击败了 69.93%的用户
var addStrings = function(num1, num2) {
let i = num1.length - 1, j = num2.length - 1, add = 0;
const ans = [];
while (i >= 0 || j >= 0 || add != 0) {
const x = i >= 0 ? num1.charAt(i) - \'0\' : 0;
const y = j >= 0 ? num2.charAt(j) - \'0\' : 0;
const result = x + y + add;
ans.push(result % 10);
add = Math.floor(result / 10);
i -= 1;
j -= 1;
}
return ans.reverse().join(\'\');
};
4. 寻找两个正序数组的中位数(2021.7.22)
/**
* @param {number[]} nums1
* @param {number[]} nums2
* @return {number}
*/
var findMedianSortedArrays = function(nums1, nums2) {
//整体思路:把这两个数组遍历按照大小顺序保存在一个新数组中,然后再更具两者长度是奇数还是偶数来输出结果
let len1 = nums1.length;
let len2 = nums2.length;
let mid = (len1+len2) /2;
let temp = 0;
let i= 0,j=0;
let arr =[];
while(i<len1 || j<len2){
if(nums1[i]<=nums2[j] || j>= len2 && i< len1){
arr[temp] = nums1[i]
i++;
}else{
arr[temp] = nums2[j]
j++;
}
temp++;
// if(temp>mid){
// break;
// }
}
let res = ((len1+len2)%2 === 1) ? arr[Math.floor(arr.length / 2)] : (arr[arr.length / 2 - 1] + arr[arr.length / 2]) / 2
return res;
};
试图优化,但失败,目前的复杂度为O(m+n),本来想判断一下temp如果大于一半的话,就提前break,但是不知道是不是js不允许arr[temp],所以解决不出来,虽然这个判断并不影响复杂度,因为官方可以给出O(log(m+n))的复杂度:可以用二分查找方法。
- 无重复字符的最长子串(2021.7.21)
给定一个字符串 s ,请你找出其中不含有重复字符的 最长子串 的长度。
/**
* @param {string} s
* @return {number}
*/
var lengthOfLongestSubstring = function(s) {
let map = new Map();
let max = 0;
let start = 0;
let end = 0;
while(end != s.length){
if(!map.has(s[end])){
} else {
start = map.get(s[end]) > start ? map.get(s[end]) : start;
}
map.set(s[end], end+1);
ans = end - start +1;
end++;
max = ans > max ? ans : max;
}
return max;
}
2.两数相加(2021.7.20)
给你两个 非空 的链表,表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的,并且每个节点只能存储 一位 数字。
请你将两个数相加,并以相同形式返回一个表示和的链表。
你可以假设除了数字 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} l1
* @param {ListNode} l2
* @return {ListNode}
*/
var addTwoNumbers = function(l1, l2) {
let temp = 0;
let head = null;
let tail = null;
while(l1 || l2){
let a = l1 ? l1.val : 0;
let b = l2 ? l2.val : 0;
let sum = a + b + temp;
if(!head){
head = tail = new ListNode(sum%10, null);
} else{
tail.next = new ListNode(sum%10);
tail = tail.next;
}
temp = sum > 9 ? 1 : 0;
if(l1){
l1 = l1.next;
}
if(l2){
l2 = l2.next;
}
}
if(temp>0){
tail.next = new ListNode(temp);
}
return head;
};
1.两数之和(2021.7.20)
给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那 两个 整数,并返回它们的数组下标。
你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。
你可以按任意顺序返回答案。
/**
* @param {number[]} nums
* @param {number} target
* @return {number[]}
*/
var twoSum = function(nums, target) {
let numsSet = new Set();
for(let i=0;i<nums.length;i++){
let temp = target-nums[i]
if(numsSet.has(temp)){
return [i,nums.indexOf(temp)]
}
numsSet.add(nums[i])
}
};
以上是关于leetcode hot100解题总结 JS(持续更新)的主要内容,如果未能解决你的问题,请参考以下文章