Code Monkey home page Code Monkey logo

tencent-50-leetcode's Introduction

tencent-50-leetcode's People

Contributors

webvueblog avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

tencent-50-leetcode's Issues

344. 反转字符串

344. 反转字符串

Description

Difficulty: 简单

Related Topics: 递归, 双指针, 字符串

编写一个函数,其作用是将输入的字符串反转过来。输入字符串以字符数组 s 的形式给出。

不要给另外的数组分配额外的空间,你必须修改输入数组、使用 O(1) 的额外空间解决这一问题。

示例 1:

输入:s = ["h","e","l","l","o"]
输出:["o","l","l","e","h"]

示例 2:

输入:s = ["H","a","n","n","a","h"]
输出:["h","a","n","n","a","H"]

提示:

  • 1 <= s.length <= 105
  • s[i] 都是 码表中的可打印字符

Solution

Language: JavaScript

/**
 * @param {character[]} s
 * @return {void} Do not return anything, modify s in-place instead.
 */
// 双指针
// var reverseString = function(s) {
//     const n = s.length;
//     for (let left = 0, right = n - 1; left < right; left++, right--) {
//         [s[left], s[right]] = [s[right], s[left]]
//     }
// };

var reverseString = function(s) {
    let left = 0, right = s.length - 1
    while (left < right) {
        [s[left], s[right]] = [s[right], s[left]]
        left++
        right--
    }
}

5. 最长回文子串

5. 最长回文子串

Description

Difficulty: 中等

Related Topics: 字符串, 动态规划

给你一个字符串 s,找到 s 中最长的回文子串。

示例 1:

输入:s = "babad"
输出:"bab"
解释:"aba" 同样是符合题意的答案。

示例 2:

输入:s = "cbbd"
输出:"bb"

提示:

  • 1 <= s.length <= 1000
  • s 仅由数字和英文字母组成

Solution

Language: JavaScript

/**
 * @param {string} s
 * @return {string}
 */
var longestPalindrome = function(s) {
    let max = ''

    for (let i = 0; i < s.length; i++) {
        helper(i, i)
        helper(i, i+1)
    }

    function helper(l, r) {
        while(l >= 0 && r < s.length && s[l] === s[r]) {
            l--
            r++
        }
        const maxStr = s.slice(l + 1, r - 1 + 1)
        if (maxStr.length > max.length) max = maxStr
    }

    return max
};

9. 回文数

9. 回文数

Description

Difficulty: 简单

Related Topics: 数学

给你一个整数 x ,如果 x 是一个回文整数,返回 true ;否则,返回 false

回文数是指正序(从左向右)和倒序(从右向左)读都是一样的整数。

  • 例如,121 是回文,而 123 不是。

示例 1:

输入:x = 121
输出:true

示例 2:

输入:x = -121
输出:false
解释:从左向右读, 为 -121 。 从右向左读, 为 121- 。因此它不是一个回文数。

示例 3:

输入:x = 10
输出:false
解释:从右向左读, 为 01 。因此它不是一个回文数。

提示:

  • -231 <= x <= 231 - 1

**进阶:**你能不将整数转为字符串来解决这个问题吗?

Solution

Language: JavaScript

/**
 * @param {number} x
 * @return {boolean}
 */
var isPalindrome = function(x) {
    return +x.toString().split('').reverse().join('') === x;
};

46. 全排列

46. 全排列

Description

Difficulty: 中等

Related Topics: 数组, 回溯

给定一个不含重复数字的数组 nums ,返回其 所有可能的全排列 。你可以 按任意顺序 返回答案。

示例 1:

输入:nums = [1,2,3]
输出:[[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]

示例 2:

输入:nums = [0,1]
输出:[[0,1],[1,0]]

示例 3:

输入:nums = [1]
输出:[[1]]

提示:

  • 1 <= nums.length <= 6
  • -10 <= nums[i] <= 10
  • nums 中的所有整数 互不相同

Solution

Language: JavaScript

/**
 * @param {number[]} nums
 * @return {number[][]}
 * 广度优先遍历
 * 深度优先遍历
 */
var permute = function(nums) {
 nums.sort((a, b) => a - b)
 const ans = []
 const dfs = (item = []) => {
  if (item.length === nums.length) return ans.push([...item])

  nums.forEach(num => {
   if (!item.includes(num)) {
    dfs([...item, num])
   }
  })
 }
 dfs()
 return ans
};

148. 排序链表

148. 排序链表

Description

Difficulty: 中等

Related Topics: 链表, 双指针, 分治, 排序, 归并排序

给你链表的头结点 head ,请将其按 升序 排列并返回 排序后的链表

示例 1:

输入:head = [4,2,1,3]
输出:[1,2,3,4]

示例 2:

输入:head = [-1,5,3,4,0]
输出:[-1,0,3,4,5]

示例 3:

输入:head = []
输出:[]

提示:

  • 链表中节点的数目在范围 [0, 5 * 104] 内
  • -105 <= Node.val <= 105

**进阶:**你可以在 O(n log n) 时间复杂度和常数级空间复杂度下,对链表进行排序吗?

Solution

Language: JavaScript

/**
 * 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 sortList = function(head) {
    if (head === null || head.next === null) {
        return head
    }

    let midNode = getMiddleNode(head)
    let rightHead = midNode.next
    midNode.next = null

    let left = sortList(head)
    let right = sortList(rightHead)

    return mergeTwoLists(left, right)
};

// 利用快慢指针找到中间节点
var getMiddleNode = function (head) {
    if (head === null || head.next === null) {
        return head
    }
    let slow = head
    let fast = head.next.next

    while (fast !== null && fast.next !== null) {
        slow = slow.next
        fast = fast.next.next
    }

    return slow
}

// 合并两个有序链表
var mergeTwoLists = function (l1, l2) {
    const dummy = new ListNode()
    let cur = dummy
    while (l1 && l2) {
        if (l1.val < l2.val) {
            [cur.next, l1] = [l1, l1.next]
        } else {
            [cur.next, l2] = [l2, l2.next]
        }
        cur = cur.next
    }
    cur.next = l1 ? l1 : l2
    return dummy.next
}

4. 寻找两个正序数组的中位数

4. 寻找两个正序数组的中位数

Description

Difficulty: 困难

Related Topics: 数组, 二分查找, 分治

给定两个大小分别为 mn 的正序(从小到大)数组 nums1 和 nums2。请你找出并返回这两个正序数组的 中位数

算法的时间复杂度应该为 O(log (m+n))

示例 1:

输入:nums1 = [1,3], nums2 = [2]
输出:2.00000
解释:合并数组 = [1,2,3] ,中位数 2

示例 2:

输入:nums1 = [1,2], nums2 = [3,4]
输出:2.50000
解释:合并数组 = [1,2,3,4] ,中位数 (2 + 3) / 2 = 2.5

提示:

  • nums1.length == m
  • nums2.length == n
  • 0 <= m <= 1000
  • 0 <= n <= 1000
  • 1 <= m + n <= 2000
  • -106 <= nums1[i], nums2[i] <= 106

Solution

Language: JavaScript

/**
 * @param {number[]} nums1
 * @param {number[]} nums2
 * @return {number}
 */
var findMedianSortedArrays = function(nums1, nums2) {
    const newNums = nums1.concat(nums2).sort((a, b) => a - b)
    const len = newNums.length
    if (len % 2 === 0) {
        return (newNums[len/2 - 1] + newNums[len/2]) / 2
    } else {
        return newNums[Math.floor(len/2)]
    }
};

169. 多数元素

169. 多数元素

Description

Difficulty: 简单

Related Topics: 数组, 哈希表, 分治, 计数, 排序

给定一个大小为 n的数组 nums ,返回其中的多数元素。多数元素是指在数组中出现次数 大于 ⌊ n/2 ⌋ 的元素。

你可以假设数组是非空的,并且给定的数组总是存在多数元素。

示例 1:

输入:nums = [3,2,3]
输出:3

示例 2:

输入:nums = [2,2,1,1,1,2,2]
输出:2

提示:

  • n == nums.length
  • 1 <= n <= 5 * 104
  • -109 <= nums[i] <= 109

**进阶:**尝试设计时间复杂度为 O(n)、空间复杂度为 O(1) 的算法解决此问题。

Solution

Language: JavaScript

/**
 * @param {number[]} nums
 * @return {number}
 */
var majorityElement = function(nums) {
    let temp = nums[0]
    let times = 1
    for (let i = 1; i < nums.length; i++) {
        if (nums[i] === temp) {
            times++
        } else {
            times--
            if (times === 0) {
                temp = nums[i + 1]
                times = 1
                i++
            }
        }
    }
    return temp
};

// 排序 
// var majorityElement = function(nums) {
//     nums.sort((a, b) => a - b)
//     return nums[Math.floor(nums.length / 2)]
// }

206. 反转链表

206. 反转链表

Description

Difficulty: 简单

Related Topics: 递归, 链表

给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。

示例 1:

输入:head = [1,2,3,4,5]
输出:[5,4,3,2,1]

示例 2:

输入:head = [1,2]
输出:[2,1]

示例 3:

输入:head = []
输出:[]

提示:

  • 链表中节点的数目范围是 [0, 5000]
  • -5000 <= Node.val <= 5000

**进阶:**链表可以选用迭代或递归方式完成反转。你能否用两种方法解决这道题?

Solution

Language: JavaScript

/**
 * 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}
 */
// 假设链表为 1→2→3→∅,我们想要把它改成 ∅←1←2←3。
// 迭代
var reverseList = function(head) {
    let prev = null
    let curr = head
    while (curr) {
        [curr.next, prev, curr] = [prev, curr, curr.next]
    }
    return prev
};

// 递归
// var reverseList = function(head) {
//     if (head === null || head.next === null) {
//         return head
//     }

//     const nextHead = reverseList(head.next)
//     head.next.next = head
//     head.next = null
//     return nextHead
// }

33. 搜索旋转排序数组

33. 搜索旋转排序数组

Description

Difficulty: 中等

Related Topics: 数组, 二分查找

整数数组 nums 按升序排列,数组中的值 互不相同

在传递给函数之前,nums 在预先未知的某个下标 k0 <= k < nums.length)上进行了 旋转,使数组变为 [nums[k], nums[k+1], ..., nums[n-1], nums[0], nums[1], ..., nums[k-1]](下标 从 0 开始 计数)。例如, [0,1,2,4,5,6,7] 在下标 3 处经旋转后可能变为 [4,5,6,7,0,1,2]

给你 旋转后 的数组 nums 和一个整数 target ,如果 nums 中存在这个目标值 target ,则返回它的下标,否则返回 -1 。

你必须设计一个时间复杂度为 O(log n) 的算法解决此问题。

示例 1:

输入:nums = [4,5,6,7,0,1,2], target = 0
输出:4

示例 2:

输入:nums = [4,5,6,7,0,1,2], target = 3
输出:-1

示例 3:

输入:nums = [1], target = 0
输出:-1

提示:

  • 1 <= nums.length <= 5000
  • -104 <= nums[i] <= 104
  • nums 中的每个值都 独一无二
  • 题目数据保证 nums 在预先未知的某个下标上进行了旋转
  • -104 <= target <= 104

Solution

Language: JavaScript

/**
 * @param {number[]} nums
 * @param {number} target
 * @return {number}
 * 二分搜索
 * 关键字:排序,搜索
 */
var search = function(nums, target) {
 let [left, right] = [0, nums.length - 1]
 
 while (left <= right) {
  const mid = (left + right) >>> 1
  if (nums[mid] === target) return mid

  if (nums[mid] > nums[right]) {
   if (nums[left] <= target && nums[mid] > target) right = mid - 1
   else left = mid + 1
  } else {
   if (nums[mid] < target && nums[right] >= target) left = mid + 1
   else right = mid - 1
  }
 }
 return -1
}

15. 三数之和

15. 三数之和

Description

Difficulty: 中等

Related Topics: 数组, 双指针, 排序

给你一个整数数组 nums ,判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i != ji != kj != k ,同时还满足 nums[i] + nums[j] + nums[k] == 0 。请

你返回所有和为 0 且不重复的三元组。

**注意:**答案中不可以包含重复的三元组。

示例 1:

输入:nums = [-1,0,1,2,-1,-4]
输出:[[-1,-1,2],[-1,0,1]]
解释:
nums[0] + nums[1] + nums[2] = (-1) + 0 + 1 = 0 。
nums[1] + nums[2] + nums[4] = 0 + 1 + (-1) = 0 。
nums[0] + nums[3] + nums[4] = (-1) + 2 + (-1) = 0 。
不同的三元组是 [-1,0,1] 和 [-1,-1,2] 。
注意,输出的顺序和三元组的顺序并不重要。

示例 2:

输入:nums = [0,1,1]
输出:[]
解释:唯一可能的三元组和不为 0 。

示例 3:

输入:nums = [0,0,0]
输出:[[0,0,0]]
解释:唯一可能的三元组和为 0 。

提示:

  • 3 <= nums.length <= 3000
  • -105 <= nums[i] <= 105

Solution

Language: JavaScript

/**
 * @param {number[]} nums
 * @return {number[][]}
 */
var threeSum = function(nums) {
    let ans = []
    const len = nums.length
    if (nums === null || len < 3) return ans
    nums.sort((a, b) => a - b)

    for (let i = 0; i < nums.length; i++) {
        if (nums[0] > 0) break
        if (i > 0 && nums[i] === nums[i-1]) continue
        let l = i + 1
        let r = len - 1
        while (l < r) {
            const sum = nums[i] + nums[l] + nums[r]
            if (sum === 0) {
                ans.push([nums[i], nums[l], nums[r]])
                while (l<r && nums[l] === nums[l+1]) l++
                while (l<r && nums[r] === nums[r-1]) r--
                l++
                r--
            }
            else if (sum < 0) l++
            else if (sum > 0) r--
        }
    }

    return ans
}

26. 删除有序数组中的重复项

26. 删除有序数组中的重复项

Description

Difficulty: 简单

Related Topics: 数组, 双指针

给你一个 升序排列 的数组 nums ,请你 删除重复出现的元素,使每个元素 只出现一次 ,返回删除后数组的新长度。元素的 相对顺序 应该保持 一致

由于在某些语言中不能改变数组的长度,所以必须将结果放在数组nums的第一部分。更规范地说,如果在删除重复项之后有 k 个元素,那么 nums 的前 k 个元素应该保存最终结果。

将最终结果插入 nums 的前 k 个位置后返回 k

不要使用额外的空间,你必须在 修改输入数组 并在使用 O(1) 额外空间的条件下完成。

判题标准:

系统会用下面的代码来测试你的题解:

int[] nums = [...]; // 输入数组
int[] expectedNums = [...]; // 长度正确的期望答案

int k = removeDuplicates(nums); // 调用

assert k == expectedNums.length;
for (int i = 0; i < k; i++) {
    assert nums[i] == expectedNums[i];
}

如果所有断言都通过,那么您的题解将被 通过

示例 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 。不需要考虑数组中超出新长度后面的元素。

提示:

  • 1 <= nums.length <= 3 * 104
  • -104 <= nums[i] <= 104
  • nums 已按 升序 排列

Solution

Language: JavaScript

/**
 * @param {number[]} nums
 * @return {number}
 */
var removeDuplicates = function(nums) {
    let slow = 0
    let fast = 0
    while (fast < nums.length) {
        if (nums[fast] !== nums[slow]) {
            slow++
            nums[slow] = nums[fast]
        }
        fast++
    }
    return slow + 1
};

155. 最小栈

155. 最小栈

Description

Difficulty: 中等

Related Topics: , 设计

设计一个支持 pushpoptop 操作,并能在常数时间内检索到最小元素的栈。

实现 MinStack 类:

  • MinStack() 初始化堆栈对象。
  • void push(int val) 将元素val推入堆栈。
  • void pop() 删除堆栈顶部的元素。
  • int top() 获取堆栈顶部的元素。
  • int getMin() 获取堆栈中的最小元素。

示例 1:

输入:
["MinStack","push","push","push","getMin","pop","top","getMin"]
[[],[-2],[0],[-3],[],[],[],[]]

输出:
[null,null,null,null,-3,null,0,-2]

解释:
MinStack minStack = new MinStack();
minStack.push(-2);
minStack.push(0);
minStack.push(-3);
minStack.getMin();   --> 返回 -3.
minStack.pop();
minStack.top();      --> 返回 0.
minStack.getMin();   --> 返回 -2.

提示:

  • -231 <= val <= 231 - 1
  • poptopgetMin 操作总是在 非空栈 上调用
  • pushpoptop, and getMin最多被调用 3 * 104 次

Solution

Language: JavaScript

// stack正常push,min_stack只会push需要入栈和栈顶中较小的元素
// stack正常pop,min_stack正常pop
// 返回stack栈顶元素
// 返回min_stack栈顶元素
var MinStack = function() {
    this.stack = [];
    this.min_stack = [Infinity]
};

MinStack.prototype.push = function(x) {
    this.stack.push(x)
    this.min_stack.push(Math.min(x, this.min_stack[this.min_stack.length - 1]))
};

MinStack.prototype.pop = function() {
    this.stack.pop()
    this.min_stack.pop()
};

MinStack.prototype.top = function() {
    return this.stack[this.stack.length - 1]
};

MinStack.prototype.getMin = function() {
    return this.min_stack[this.min_stack.length - 1]
};

124. 二叉树中的最大路径和

124. 二叉树中的最大路径和

Description

Difficulty: 困难

Related Topics: , 深度优先搜索, 动态规划, 二叉树

路径 被定义为一条从树中任意节点出发,沿父节点-子节点连接,达到任意节点的序列。同一个节点在一条路径序列中 至多出现一次 。该路径 至少包含一个 节点,且不一定经过根节点。

路径和 是路径中各节点值的总和。

给你一个二叉树的根节点 root ,返回其 最大路径和

示例 1:

输入:root = [1,2,3]
输出:6
解释:最优路径是 2 -> 1 -> 3 ,路径和为 2 + 1 + 3 = 6

示例 2:

输入:root = [-10,9,20,null,null,15,7]
输出:42
解释:最优路径是 15 -> 20 -> 7 ,路径和为 15 + 20 + 7 = 42

提示:

  • 树中节点数目范围是 [1, 3 * 104]
  • -1000 <= Node.val <= 1000

Solution

Language: JavaScript

/**
 * Definition for a binary tree node.
 * function TreeNode(val, left, right) {
 *     this.val = (val===undefined ? 0 : val)
 *     this.left = (left===undefined ? null : left)
 *     this.right = (right===undefined ? null : right)
 * }
 */
/**
 * @param {TreeNode} root
 * @return {number}
 */
// DFS
var maxPathSum = function(root) {
    let ans = -Infinity
    dfs(root)
    return ans

    function dfs(root) {
        if (!root) return 0
        let left = dfs(root.left)
        let right = dfs(root.right)
        ans = Math.max(ans, root.val + left + right)
        return Math.max(0, Math.max(left, right) + root.val)
    }
};

8. 字符串转换整数 (atoi)

8. 字符串转换整数 (atoi)

Description

Difficulty: 中等

Related Topics: 字符串

请你来实现一个 myAtoi(string s) 函数,使其能将字符串转换成一个 32 位有符号整数(类似 C/C++ 中的 atoi 函数)。

函数 myAtoi(string s) 的算法如下:

  1. 读入字符串并丢弃无用的前导空格
  2. 检查下一个字符(假设还未到字符末尾)为正还是负号,读取该字符(如果有)。 确定最终结果是负数还是正数。 如果两者都不存在,则假定结果为正。
  3. 读入下一个字符,直到到达下一个非数字字符或到达输入的结尾。字符串的其余部分将被忽略。
  4. 将前面步骤读入的这些数字转换为整数(即,"123" -> 123, "0032" -> 32)。如果没有读入数字,则整数为 0 。必要时更改符号(从步骤 2 开始)。
  5. 如果整数数超过 32 位有符号整数范围 [−231,  231 − 1] ,需要截断这个整数,使其保持在这个范围内。具体来说,小于 −231 的整数应该被固定为 −231 ,大于 231 − 1 的整数应该被固定为 231 − 1 。
  6. 返回整数作为最终结果。

注意:

  • 本题中的空白字符只包括空格字符 ' '
  • 除前导空格或数字后的其余字符串外,请勿忽略 任何其他字符。

示例 1:

输入:s = "42"
输出:42
解释:加粗的字符串为已经读入的字符,插入符号是当前读取的字符。
第 1 步:"42"(当前没有读入字符,因为没有前导空格)
         ^
第 2 步:"42"(当前没有读入字符,因为这里不存在 '-' 或者 '+')
         ^
第 3 步:"42"(读入 "42")
           ^
解析得到整数 42 。
由于 "42" 在范围 [-231, 231 - 1] 内,最终结果为 42 。

示例 2:

输入:s = "   -42"
输出:-42
解释:
第 1 步:"   -42"(读入前导空格,但忽视掉)
            ^
第 2 步:"   -42"(读入 '-' 字符,所以结果应该是负数)
             ^
第 3 步:"   -42"(读入 "42")
               ^
解析得到整数 -42 。
由于 "-42" 在范围 [-231, 231 - 1] 内,最终结果为 -42 。

示例 3:

输入:s = "4193 with words"
输出:4193
解释:
第 1 步:"4193 with words"(当前没有读入字符,因为没有前导空格)
         ^
第 2 步:"4193 with words"(当前没有读入字符,因为这里不存在 '-' 或者 '+')
         ^
第 3 步:"4193 with words"(读入 "4193";由于下一个字符不是一个数字,所以读入停止)
             ^
解析得到整数 4193 。
由于 "4193" 在范围 [-231, 231 - 1] 内,最终结果为 4193 。

提示:

  • 0 <= s.length <= 200
  • s 由英文字母(大写和小写)、数字(0-9)、' ''+''-''.' 组成

Solution

Language: JavaScript

/**
 * @param {string} s
 * @return {number}
 */
var myAtoi = function(s) {
    const number = parseInt(str, 10)

    if (isNaN(number)) {
        return 0
    } else if (number < Math.pow(-2, 31) || number > Math.pow(2, 31) - 1) {
        return number < Math.pow(-2, 31) ? Math.pow(-2, 31) : Math.pow(2, 31) - 1
    } else {
        return number
    }
};

21. 合并两个有序链表

21. 合并两个有序链表

Description

Difficulty: 简单

Related Topics: 递归, 链表

将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。 

示例 1:

输入:l1 = [1,2,4], l2 = [1,3,4]
输出:[1,1,2,3,4,4]

示例 2:

输入:l1 = [], l2 = []
输出:[]

示例 3:

输入:l1 = [], l2 = [0]
输出:[0]

提示:

  • 两个链表的节点数目范围是 [0, 50]
  • -100 <= Node.val <= 100
  • l1l2 均按 非递减顺序 排列

Solution

Language: JavaScript

/**
 * 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) {
//         return list2
//     } else if (!list2) {
//         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
//     }
// }

// 迭代
var mergeTwoLists = function(list1, list2) {
    const dummy = new ListNode()
    let curr = dummy
    while (list1 && list2) {
        list1.val < list2.val
            ? [curr.next, list1] = [list1, list1.next]
            : [curr.next, list2] = [list2, list2.next]
        curr = curr.next
    }
    // curr.next = list1 ? list1 : list2
    curr.next = list1 ?? list2
    return dummy.next
}

238. 除自身以外数组的乘积

238. 除自身以外数组的乘积

Description

Difficulty: 中等

Related Topics: 数组, 前缀和

给你一个整数数组 nums,返回 数组 answer ,其中 answer[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积 。

题目数据 保证 数组 nums之中任意元素的全部前缀元素和后缀的乘积都在  32 位 整数范围内。

请**不要使用除法,**且在 O(_n_) 时间复杂度内完成此题。

示例 1:

输入: nums = [1,2,3,4]
输出: [24,12,8,6]

示例 2:

输入: nums = [-1,1,0,-3,3]
输出: [0,0,9,0,0]

提示:

  • 2 <= nums.length <= 105
  • -30 <= nums[i] <= 30
  • 保证 数组 nums之中任意元素的全部前缀元素和后缀的乘积都在  32 位 整数范围内

进阶:你可以在 O(1) 的额外空间复杂度内完成这个题目吗?( 出于对空间复杂度分析的目的,输出数组不被视为额外空间。)

Solution

Language: JavaScript

/**
 * @param {number[]} nums
 * @return {number[]}
 */
// 从左往右遍历: 记录从左到当前位置前一位的乘积
// 从右往左遍历: 从左到当前位置前一位的乘积 乘上 右边元素的积
var productExceptSelf = function(nums) {
    const res = []
    res[0] = 1
    for (let i = 1; i < nums.length; i++) {
        res[i] = res[i - 1] * nums[i - 1]
    }
    let right = 1
    for (let j = nums.length - 1; j >= 0; j--) {
        res[j] *= right
        right *= nums[j]
    }
    return res
};

78. 子集

78. 子集

Description

Difficulty: 中等

Related Topics: 位运算, 数组, 回溯

给你一个整数数组 nums ,数组中的元素 互不相同 。返回该数组所有可能的子集(幂集)。

解集 不能 包含重复的子集。你可以按 任意顺序 返回解集。

示例 1:

输入:nums = [1,2,3]
输出:[[],[1],[2],[1,2],[3],[1,3],[2,3],[1,2,3]]

示例 2:

输入:nums = [0]
输出:[[],[0]]

提示:

  • 1 <= nums.length <= 10
  • -10 <= nums[i] <= 10
  • nums 中的所有元素 互不相同

Solution

Language: JavaScript

/**
 * @param {number[]} nums
 * @return {number[][]}
 */
// 递归法实现子集枚举
// var subsets = function (nums) {
//     let result = []
//     let path = []
//     function backtracking(startIndex) {
//         result.push(path.slice())
//         for (let i = startIndex; i < nums.length; i++) {
//             path.push(nums[i])
//             backtracking(i + 1)
//             path.pop()
//         }
//     }
//     backtracking(0)
//     return result
// }

// DFS回溯思路
var subsets = function (nums) {
 const res = []
 const dfs = (index, list) => {
  res.push(list.slice())
  for (let i = index; i < nums.length; i++) {
   list.push(nums[i])
   dfs(i + 1, list)
   list.pop()
  }
 }
 dfs(0, [])
 return res
}

20. 有效的括号

20. 有效的括号

Description

Difficulty: 简单

Related Topics: , 字符串

给定一个只包括 '('')''{''}''['']' 的字符串 s ,判断字符串是否有效。

有效字符串需满足:

  1. 左括号必须用相同类型的右括号闭合。
  2. 左括号必须以正确的顺序闭合。

示例 1:

输入:s = "()"
输出:true

示例 2:

输入:s = "()[]{}"
输出:true

示例 3:

输入:s = "(]"
输出:false

示例 4:

输入:s = "([)]"
输出:false

示例 5:

输入:s = "{[]}"
输出:true

提示:

  • 1 <= s.length <= 104
  • s 仅由括号 '()[]{}' 组成

Solution

Language: JavaScript

/**
 * @param {string} s
 * @return {boolean}
 */
var isValid = function(s) {
    if (s.length % 2 !== 0) return false
    const map = {
        '(' : ')',
        '{' : '}',
        '[' : ']'
    };
    let stack = []
    for (let char of s) {
        if (map[char]) {
            stack.push(map[char])
        } else {
            let ret = stack.pop()
            if (ret !== char) {
                return false
            }
        }
    }
    return stack.length === 0
};

61. 旋转链表

61. 旋转链表

Description

Difficulty: 中等

Related Topics: 链表, 双指针

给你一个链表的头节点 head ,旋转链表,将链表每个节点向右移动 k个位置。

示例 1:

输入:head = [1,2,3,4,5], k = 2
输出:[4,5,1,2,3]

示例 2:

输入:head = [0,1,2], k = 4
输出:[2,0,1]

提示:

  • 链表中节点的数目在范围 [0, 500]
  • -100 <= Node.val <= 100
  • 0 <= k <= 2 * 109

Solution

Language: JavaScript

/**
 * Definition for singly-linked list.
 * function ListNode(val, next) {
 *     this.val = (val===undefined ? 0 : val)
 *     this.next = (next===undefined ? null : next)
 * }
 */
/**
 * @param {ListNode} head
 * @param {number} k
 * @return {ListNode}
 */
// 闭合为环
var rotateRight = function(head, k) {
    if (k === 0 || !head || !head.next) {
        return head
    }

    let len = 1
    let cur = head
    while (cur.next) {
        cur = cur.next
        len++;
    }

    cur.next = head
    k = len - k % len
    
    while (k--) {
        cur = cur.next
    }
    head = cur.next
    cur.next = null
    return head
};

122. 买卖股票的最佳时机 II

122. 买卖股票的最佳时机 II

Description

Difficulty: 中等

Related Topics: 贪心, 数组, 动态规划

给你一个整数数组 prices ,其中 prices[i] 表示某支股票第 i 天的价格。

在每一天,你可以决定是否购买和/或出售股票。你在任何时候 最多 只能持有 一股 股票。你也可以先购买,然后在 同一天 出售。

返回 你能获得的 最大 利润 。

示例 1:

输入:prices = [7,1,5,3,6,4]
输出:7
解释:在第 2 天(股票价格 = 1)的时候买入,在第 3 天(股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5 - 1 = 4 。
     随后,在第 4 天(股票价格 = 3)的时候买入,在第 5 天(股票价格 = 6)的时候卖出, 这笔交易所能获得利润 = 6 - 3 = 3 。
     总利润为 4 + 3 = 7 。

示例 2:

输入:prices = [1,2,3,4,5]
输出:4
解释:在第 1 天(股票价格 = 1)的时候买入,在第 5 天 (股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5 - 1 = 4 。
     总利润为 4 。

示例 3:

输入:prices = [7,6,4,3,1]
输出:0
解释:在这种情况下, 交易无法获得正利润,所以不参与交易可以获得最大利润,最大利润为 0 。

提示:

  • 1 <= prices.length <= 3 * 104
  • 0 <= prices[i] <= 104

Solution

Language: JavaScript

/**
 * @param {number[]} prices
 * @return {number}
 */
// dp[5][0] = Math.max(dp[4][0], dp[4][1] + price[5]) // 卖
// dp[5][1] = Math.max(dp[4][1], dp[4][0] - price[5]) // 买
// 动态规划
var maxProfit = function(prices) {
    const n = prices.length;
    const dp = new Array(n).fill(0).map(() => new Array(2).fill(0))

    dp[0] = [0, -prices[0]]
    for (let i = 1; i < n; i++) {
        dp[i][0] = Math.max(dp[i-1][0], dp[i-1][1] + prices[i])
        dp[i][1] = Math.max(dp[i-1][1], dp[i-1][0] - prices[i])
    }
    return dp[n-1][0]
};

// 贪心
// var maxProfit = function(prices) {
//     let ans = 0
//     let n = prices.length
//     for (let i = 1; i < n; i++) {
//         ans += Math.max(0, prices[i] - prices[i-1])
//     }
//     return ans
// }

88. 合并两个有序数组

88. 合并两个有序数组

Description

Difficulty: 简单

Related Topics: 数组, 双指针, 排序

给你两个按 非递减顺序 排列的整数数组 nums1nums2,另有两个整数 mn ,分别表示 nums1nums2 中的元素数目。

请你 合并 nums2nums1 中,使合并后的数组同样按 非递减顺序 排列。

**注意:**最终,合并后数组不应由函数返回,而是存储在数组 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 中。

提示:

  • nums1.length == m + n
  • nums2.length == n
  • 0 <= m, n <= 200
  • 1 <= m + n <= 200
  • -109 <= nums1[i], nums2[j] <= 109

**进阶:**你可以设计实现一个时间复杂度为 O(m + n) 的算法解决此问题吗?

Solution

Language: JavaScript

/**
 * @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) {
//     for (let i = 0, len = nums1.length; i < len; i++) {
//         if (m === 0) {
//             nums1[len-1-i] = nums2[--n];
//         } else if (n === 0) {
//             break
//         } else {
//             nums1[len-1-i] = nums1[m-1] > nums2[n-1] ? nums1[--m] : nums2[--n]
//         }
//     }
// };

// 直接合并后排序
var merge = function(nums1, m, nums2, n) {
    nums1.splice(m, nums1.length - m, ...nums2)
    nums1.sort((a, b) => a - b)
}

89. 格雷编码

/**

  • @param {number} n
  • @return {number[]}
    */
    // 二进制数转格雷码
    // var grayCode = function(n) {
    // const ret = []
    // for (let i = 0; i < 1 << n; i++) {
    // ret.push((i >> 1) ^ i)
    // }
    // return ret
    // };

// 递归版
// var grayCode = function(n) {
// if (n === 0) return [0]
// if (n === 1) return [0, 1]

// let add = 1 << (n-1)
// let lastStatus = grayCode(n - 1)
// let res = [...lastStatus]

// for (let i = lastStatus.length - 1; i >= 0; i--) {
// res.push(lastStatus[i] + add)
// }
// return res
// }

var grayCode = function(n) {
let ans = [0]
let pre = 1
for (let i = 0; i < n; i++) {
for (let j = ans.length - 1; j >= 0; j--) {
ans.push(pre + ans[j])
}
pre <<= 1
}
return ans
}

146. LRU 缓存

146. LRU 缓存

Description

Difficulty: 中等

Related Topics: 设计, 哈希表, 链表, 双向链表

请你设计并实现一个满足  约束的数据结构。

实现 LRUCache 类:

  • LRUCache(int capacity)正整数 作为容量 capacity 初始化 LRU 缓存
  • int get(int key) 如果关键字 key 存在于缓存中,则返回关键字的值,否则返回 -1
  • void put(int key, int value) 如果关键字 key 已经存在,则变更其数据值 value ;如果不存在,则向缓存中插入该组 key-value 。如果插入操作导致关键字数量超过 capacity ,则应该 逐出 最久未使用的关键字。

函数 getput 必须以 O(1) 的平均时间复杂度运行。

示例:

输入
["LRUCache", "put", "put", "get", "put", "get", "put", "get", "get", "get"]
[[2], [1, 1], [2, 2], [1], [3, 3], [2], [4, 4], [1], [3], [4]]
输出
[null, null, null, 1, null, -1, null, -1, 3, 4]

解释
LRUCache lRUCache = new LRUCache(2);
lRUCache.put(1, 1); // 缓存是 {1=1}
lRUCache.put(2, 2); // 缓存是 {1=1, 2=2}
lRUCache.get(1);    // 返回 1
lRUCache.put(3, 3); // 该操作会使得关键字 2 作废,缓存是 {1=1, 3=3}
lRUCache.get(2);    // 返回 -1 (未找到)
lRUCache.put(4, 4); // 该操作会使得关键字 1 作废,缓存是 {4=4, 3=3}
lRUCache.get(1);    // 返回 -1 (未找到)
lRUCache.get(3);    // 返回 3
lRUCache.get(4);    // 返回 4

提示:

  • 1 <= capacity <= 3000
  • 0 <= key <= 10000
  • 0 <= value <= 105
  • 最多调用 2 * 105getput

Solution

Language: JavaScript

/**
 * @param {number} capacity
 */
var LRUCache = function(capacity) {
 this.map = new Map()
 this.capacity = capacity
};

/** 
 * @param {number} key
 * @return {number}
 */
LRUCache.prototype.get = function(key) {
 if (this.map.has(key)) {
  let value = this.map.get(key)
  // 重新set,相当于更新到 map 最后
  this.map.delete(key)
  this.map.set(key, value)
  return value
 }
 return -1
};

/** 
 * @param {number} key 
 * @param {number} value
 * @return {void}
 */
LRUCache.prototype.put = function(key, value) {
 if (this.map.has(key)) {
  this.map.delete(key)
 }

 this.map.set(key, value)

 if (this.map.size > this.capacity) {
  this.map.delete(this.map.keys().next().value)
 }
};

/**

53. 最大子数组和

53. 最大子数组和

Description

Difficulty: 中等

Related Topics: 数组, 分治, 动态规划

给你一个整数数组 nums ,请你找出一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。

子数组 是数组中的一个连续部分。

示例 1:

输入:nums = [-2,1,-3,4,-1,2,1,-5,4]
输出:6
解释:连续子数组 [4,-1,2,1] 的和最大,为 6 。

示例 2:

输入:nums = [1]
输出:1

示例 3:

输入:nums = [5,4,-1,7,8]
输出:23

提示:

  • 1 <= nums.length <= 105
  • -104 <= nums[i] <= 104

**进阶:**如果你已经实现复杂度为 O(n) 的解法,尝试使用更为精妙的 分治法 求解。

Solution

Language: JavaScript

/**
 * @param {number[]} nums
 * @return {number}
 */
var maxSubArray = function(nums) {
 let [pre, maxAns] = [0, nums[0]]
 nums.forEach((x) => {
  pre = Math.max(pre + x, x)
  maxAns = Math.max(maxAns, pre)
 })
 return maxAns
};

235. 二叉搜索树的最近公共祖先

235. 二叉搜索树的最近公共祖先

Description

Difficulty: 简单

Related Topics: , 深度优先搜索, 二叉搜索树, 二叉树

给定一个二叉搜索树, 找到该树中两个指定节点的最近公共祖先。

中最近公共祖先的定义为:“对于有根树 T 的两个结点 p、q,最近公共祖先表示为一个结点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。”

例如,给定如下二叉搜索树:  root = [6,2,8,0,4,7,9,null,null,3,5]

示例 1:

输入: root = [6,2,8,0,4,7,9,null,null,3,5], p = 2, q = 8
输出: 6 
解释: 节点 2 和节点 8 的最近公共祖先是 6。

示例 2:

输入: root = [6,2,8,0,4,7,9,null,null,3,5], p = 2, q = 4
输出: 2
解释: 节点 2 和节点 4 的最近公共祖先是 2, 因为根据定义最近公共祖先节点可以为节点本身。

说明:

  • 所有节点的值都是唯一的。
  • p、q 为不同节点且均存在于给定的二叉搜索树中。

Solution

Language: JavaScript

/**
 * Definition for a binary tree node.
 * function TreeNode(val) {
 *     this.val = val;
 *     this.left = this.right = null;
 * }
 */

/**
 * @param {TreeNode} root
 * @param {TreeNode} p
 * @param {TreeNode} q
 * @return {TreeNode}
 */
// 递归 
var lowestCommonAncestor = function(root, p, q) {
    if (p.val < root.val  && q.val < root.val) {
        return lowestCommonAncestor(root.left, p, q)
    }
    if (p.val > root.val && q.val > root.val) {
        return lowestCommonAncestor(root.right, p, q)
    }
    return root
};

// 迭代
// var lowestCommonAncestor = function(root, p, q) {
//     while (root) {
//         if (p.val < root.val && q.val < root.val) {
//             root = root.left
//         } else if (p.val > root.val && q.val > root.val) {
//             root = root.right
//         } else {
//             break
//         }
//     }
//     return root
// }

231. 2 的幂

231. 2 的幂

Description

Difficulty: 简单

Related Topics: 位运算, 递归, 数学

给你一个整数 n,请你判断该整数是否是 2 的幂次方。如果是,返回 true ;否则,返回 false

如果存在一个整数 x 使得 n == 2x ,则认为 n 是 2 的幂次方。

示例 1:

输入:n = 1
输出:true
解释:20 = 1

示例 2:

输入:n = 16
输出:true
解释:24 = 16

示例 3:

输入:n = 3
输出:false

示例 4:

输入:n = 4
输出:true

示例 5:

输入:n = 5
输出:false

提示:

  • -231 <= n <= 231 - 1

**进阶:**你能够不使用循环/递归解决此问题吗?

Solution

Language: JavaScript

/**
 * @param {number} n
 * @return {boolean}
 */
// 二进制表示
// var isPowerOfTwo = function(n) {
//     return n > 0 && (n & (n - 1)) === 0
// };

// var isPowerOfTwo = function(n) {
//     return n > 0 && (n & -n) === n
// };


var isPowerOfTwo = function(n) {
    if (n <= 0) return false
    return (n & (n-1)) === 0
};

62. 不同路径

62. 不同路径

Description

Difficulty: 中等

Related Topics: 数学, 动态规划, 组合数学

一个机器人位于一个 m x n网格的左上角 (起始点在下图中标记为 “Start” )。

机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为 “Finish” )。

问总共有多少条不同的路径?

示例 1:

输入:m = 3, n = 7
输出:28

示例 2:

输入:m = 3, n = 2
输出:3
解释:
从左上角开始,总共有 3 条路径可以到达右下角。
1\. 向右 -> 向下 -> 向下
2\. 向下 -> 向下 -> 向右
3\. 向下 -> 向右 -> 向下

示例 3:

输入:m = 7, n = 3
输出:28

示例 4:

输入:m = 3, n = 3
输出:6

提示:

  • 1 <= m, n <= 100
  • 题目数据保证答案小于等于 2 * 109

Solution

Language: JavaScript

/**
 * @param {number} m
 * @param {number} n
 * @return {number}
 * 思路:
 * 每一格的路径由其上一格和左一格决定。
 * 方法:动态规划
 * 动态方程:dp[i][j] = dp[i-1][j] + dp[i][j-1]
 * 注意:对于第一行 dp[0][j],或者第一列 dp[i][0],由于都是在边界,所以只能为1
 * 建立m*n的矩阵,注意第0行和第0列元素均为1
 */
var uniquePaths = function(m, n) {
 const dp = new Array(m).fill(0).map(() => new Array(n).fill(0))

 for (let i = 0; i < m; i++) {
  dp[i][0] = 1
 }

 for (let j = 0; j < n; j++) {
  dp[0][j] = 1
 }

 for (let i = 1; i < m; i++) {
  for (let j = 1; j < n; j++) {
   dp[i][j] = dp[i-1][j] + dp[i][j-1]
  }
 }

 return dp[m-1][n-1]
}

142. 环形链表 II

142. 环形链表 II

Description

Difficulty: 中等

Related Topics: 哈希表, 链表, 双指针

给定一个链表的头节点  head ,返回链表开始入环的第一个节点。 如果链表无环,则返回 null

如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。如果 pos-1,则在该链表中没有环。注意:pos 不作为参数进行传递,仅仅是为了标识链表的实际情况。

不允许修改 链表。

示例 1:

输入:head = [3,2,0,-4], pos = 1
输出:返回索引为 1 的链表节点
解释:链表中有一个环,其尾部连接到第二个节点。

示例 2:

输入:head = [1,2], pos = 0
输出:返回索引为 0 的链表节点
解释:链表中有一个环,其尾部连接到第一个节点。

示例 3:

输入:head = [1], pos = -1
输出:返回 null
解释:链表中没有环。

提示:

  • 链表中节点的数目范围在范围 [0, 104] 内
  • -105 <= Node.val <= 105
  • pos 的值为 -1 或者链表中的一个有效索引

**进阶:**你是否可以使用 O(1) 空间解决此题?

Solution

Language: JavaScript

/**
 * Definition for singly-linked list.
 * function ListNode(val) {
 *     this.val = val;
 *     this.next = null;
 * }
 */

/**
 * @param {ListNode} head
 * @return {ListNode}
 */
// 快慢指针
// 快慢指针初始化指向 head
// 快指针走到末尾时停止
// 慢指针走一步,快指针走两步
// 快慢指针相遇,说明含有环
// 任一一节点指向头节点
// 同步向前进
// 返回入口节点
var detectCycle = function(head) {
    let slow = head
    let fast = head
    while (fast && fast.next) {
        slow = slow.next
        fast = fast.next.next
        if (slow === fast) {
            fast = head
            while (fast !== slow) {
                fast = fast.next
                slow = slow.next
            }
            return fast
        }
    }
    return null
}

// 哈希表
// var detectCycle = function(head) {
//     const map = new Map()
//     let p = head
//     while (p) {
//         if (map.get(p)) return p
//         else {
//             map.set(p, p.val)
//             p = p.next
//         }
//     }
//     return null
// }

// var detectCycle = function(head) {
//     const set = new Set()
//     while (head) {
//         if (set.has(head)) return head
//         else {
//             set.add(head)
//             head = head.next
//         }
//     }
//     return null
// }

11. 盛最多水的容器

11. 盛最多水的容器

Description

Difficulty: 中等

Related Topics: 贪心, 数组, 双指针

给定一个长度为 n 的整数数组 height 。有 n 条垂线,第 i 条线的两个端点是 (i, 0) 和 (i, height[i]) 。

找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。

返回容器可以储存的最大水量。

**说明:**你不能倾斜容器。

示例 1:

输入:[1,8,6,2,5,4,8,3,7]
输出:49 
解释:图中垂直线代表输入数组 [1,8,6,2,5,4,8,3,7]。在此情况下,容器能够容纳水(表示为蓝色部分)的最大值为 49。

示例 2:

输入:height = [1,1]
输出:1

提示:

  • n == height.length
  • 2 <= n <= 105
  • 0 <= height[i] <= 104

Solution

Language: JavaScript

/**
 * @param {number[]} height
 * @return {number}
 */
var maxArea = function(height) {
    let [l, r, ans] = [0, height.length - 1, 0]

    while (l < r) {
        let [lh, lr] = [height[l], height[r]]
        ans = Math.max(ans, Math.min(lh, lr) * (r - l))

        lh < lr ? l++ : r--
    }

    return ans
};

160. 相交链表

160. 相交链表

Description

Difficulty: 简单

Related Topics: 哈希表, 链表, 双指针

给你两个单链表的头节点 headAheadB ,请你找出并返回两个单链表相交的起始节点。如果两个链表不存在相交节点,返回 null

图示两个链表在节点 c1 开始相交**:**

题目数据 保证 整个链式结构中不存在环。

注意,函数返回结果后,链表必须 保持其原始结构

自定义评测:

评测系统 的输入如下(你设计的程序 不适用 此输入):

  • intersectVal - 相交的起始节点的值。如果不存在相交节点,这一值为 0
  • listA - 第一个链表
  • listB - 第二个链表
  • skipA - 在 listA 中(从头节点开始)跳到交叉节点的节点数
  • skipB - 在 listB 中(从头节点开始)跳到交叉节点的节点数

评测系统将根据这些输入创建链式数据结构,并将两个头节点 headAheadB 传递给你的程序。如果程序能够正确返回相交节点,那么你的解决方案将被 视作正确答案

示例 1:

输入:intersectVal = 8, listA = [4,1,8,4,5], listB = [5,6,1,8,4,5], skipA = 2, skipB = 3
输出:Intersected at '8'
解释:相交节点的值为 8 (注意,如果两个链表相交则不能为 0)。
从各自的表头开始算起,链表 A 为 [4,1,8,4,5],链表 B 为 [5,6,1,8,4,5]。
在 A 中,相交节点前有 2 个节点;在 B 中,相交节点前有 3 个节点。
— 请注意相交节点的值不为 1,因为在链表 A 和链表 B 之中值为 1 的节点 (A 中第二个节点和 B 中第三个节点) 是不同的节点。换句话说,它们在内存中指向两个不同的位置,而链表 A 和链表 B 中值为 8 的节点 (A 中第三个节点,B 中第四个节点) 在内存中指向相同的位置。

示例 2:

输入:intersectVal = 2, listA = [1,9,1,2,4], listB = [3,2,4], skipA = 3, skipB = 1
输出:Intersected at '2'
解释:相交节点的值为 2 (注意,如果两个链表相交则不能为 0)。
从各自的表头开始算起,链表 A 为 [1,9,1,2,4],链表 B 为 [3,2,4]。
在 A 中,相交节点前有 3 个节点;在 B 中,相交节点前有 1 个节点。

示例 3:

输入:intersectVal = 0, listA = [2,6,4], listB = [1,5], skipA = 3, skipB = 2
输出:null
解释:从各自的表头开始算起,链表 A 为 [2,6,4],链表 B 为 [1,5]。
由于这两个链表不相交,所以 intersectVal 必须为 0,而 skipA 和 skipB 可以是任意值。
这两个链表不相交,因此返回 null 。

提示:

  • listA 中节点数目为 m
  • listB 中节点数目为 n
  • 1 <= m, n <= 3 * 104
  • 1 <= Node.val <= 105
  • 0 <= skipA <= m
  • 0 <= skipB <= n
  • 如果 listAlistB 没有交点,intersectVal0
  • 如果 listAlistB 有交点,intersectVal == listA[skipA] == listB[skipB]

**进阶:**你能否设计一个时间复杂度 O(m + n) 、仅用 O(1) 内存的解决方案?

Solution

Language: JavaScript

/**
 * Definition for singly-linked list.
 * function ListNode(val) {
 *     this.val = val;
 *     this.next = null;
 * }
 */

/**
 * @param {ListNode} headA
 * @param {ListNode} headB
 * @return {ListNode}
 */
// 哈希集合
// var getIntersectionNode = function(headA, headB) {
//     const set = new Set()
//     let temp = headA
//     while (temp) {
//         set.add(temp)
//         temp = temp.next
//     }
//     temp = headB
//     while (temp) {
//         if (set.has(temp)) return temp
//         temp = temp.next
//     }
//     return null
// }

// 哈希集合
// var getIntersectionNode = function(headA, headB) {
//     const map = new Map()
//     let temp = headA
//     while (temp) {
//         map.set(temp)
//         temp = temp.next
//     }
//     temp = headB
//     while (temp) {
//         if (map.has(temp)) return temp
//         temp = temp.next
//     }
//     return null
// }

// 双指针
var getIntersectionNode = function(headA, headB) {
    if (headA === null || headB === null) return null
    let pA = headA, pB = headB
    while (pA !== pB) {
        pA = pA === null ? headB : pA.next
        pB = pB === null ? headA : pB.next
    }
    return pA
}

43. 字符串相乘

43. 字符串相乘

Description

Difficulty: 中等

Related Topics: 数学, 字符串, 模拟

给定两个以字符串形式表示的非负整数 num1 和 num2,返回 num1 和 num2 的乘积,它们的乘积也表示为字符串形式。

**注意:**不能使用任何内置的 BigInteger 库或直接将输入转换为整数。

示例 1:

输入: num1 = "2", num2 = "3"
输出: "6"

示例 2:

输入: num1 = "123", num2 = "456"
输出: "56088"

提示:

  • 1 <= num1.length, num2.length <= 200
  • num1 和 num2 只能由数字组成。
  • num1 和 num2 都不包含任何前导零,除了数字0本身。

Solution

Language: JavaScript

/**
 * @param {string} num1
 * @param {string} num2
 * @return {string}
 */
var multiply = function(num1, num2) {
 if (num1 === '0' || num2 === '0') return '0'
 let len1 = num1.length, len2 = num2.length, res = new Array(len1 + len2).fill(0)
 for (let i = len1 - 1; i >= 0; i--) {
  for (let j = len2 - 1; j >= 0; j--) {
   const mul = num1[i] * num2[j]
   const p1 = i + j, p2 = i + j + 1
   const sum = mul + res[p2]
   res[p1] += Math.floor(sum / 10)
   res[p2] = sum % 10
  }
 }
 if (res[0] === 0) res.shift()
 return res.join('')
};

16. 最接近的三数之和

16. 最接近的三数之和

Description

Difficulty: 中等

Related Topics: 数组, 双指针, 排序

给你一个长度为 n 的整数数组 nums和 一个目标值 target。请你从 nums中选出三个整数,使它们的和与 target 最接近。

返回这三个数的和。

假定每组输入只存在恰好一个解。

示例 1:

输入:nums = [-1,2,1,-4], target = 1
输出:2
解释:与 target 最接近的和是 2 (-1 + 2 + 1 = 2) 。

示例 2:

输入:nums = [0,0,0], target = 1
输出:0

提示:

  • 3 <= nums.length <= 1000
  • -1000 <= nums[i] <= 1000
  • -104 <= target <= 104

Solution

Language: JavaScript

/**
 * @param {number[]} nums
 * @param {number} target
 * @return {number}
 */
var threeSumClosest = function(nums, target) {
    let ans = nums[0] + nums[1] + nums[2]
    if (nums.length === 3) return ans
    nums.sort((a, b) => a - b)
    let len = nums.length

    for (let i = 0; i < len; i++) {
        let l = i + 1
        let r = len - 1
        while (l < r) {
            let tempNum = nums[i] + nums[l] + nums[r]
            if (Math.abs(target - tempNum) < Math.abs(target - ans)) {
                ans = tempNum
            }
            if (tempNum > target) {
                r--
            } else if (tempNum < target) {
                l++
            } else {
                return tempNum
            }
        }
    }

    return ans
};

14. 最长公共前缀

14. 最长公共前缀

Description

Difficulty: 简单

Related Topics: 字符串

编写一个函数来查找字符串数组中的最长公共前缀。

如果不存在公共前缀,返回空字符串 ""

示例 1:

输入:strs = ["flower","flow","flight"]
输出:"fl"

示例 2:

输入:strs = ["dog","racecar","car"]
输出:""
解释:输入不存在公共前缀。

提示:

  • 1 <= strs.length <= 200
  • 0 <= strs[i].length <= 200
  • strs[i] 仅由小写英文字母组成

Solution

Language: JavaScript

/**
 * @param {string[]} strs
 * @return {string}
 */
var longestCommonPrefix = function(strs) {
    let re = strs[0] || ''
    if (strs.length === 1) return strs[0]

    for (let i = 1; i < strs.length; i++) {
        while (strs[i].slice(0, re.length) !== re) {
            re = re.slice(0, re.length - 1)
        }
    }

    return re
};

215. 数组中的第K个最大元素

215. 数组中的第K个最大元素

Description

Difficulty: 中等

Related Topics: 数组, 分治, 快速选择, 排序, 堆(优先队列)

给定整数数组 nums 和整数 k,请返回数组中第 **k** 个最大的元素。

请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素。

你必须设计并实现时间复杂度为 O(n) 的算法解决此问题。

示例 1:

输入: [3,2,1,5,6,4], k = 2
输出: 5

示例 2:

输入: [3,2,3,1,2,4,5,5,6], k = 4
输出: 4

提示:

  • 1 <= k <= nums.length <= 105
  • -104 <= nums[i] <= 104

Solution

Language: JavaScript

/**
 * @param {number[]} nums
 * @param {number} k
 * @return {number}
 */
// 数组排序,取第 k 个数
// var findKthLargest = function (nums, k) {
//     nums.sort((a, b) => b - a).slice(0, k)
//     return nums[k - 1]
// };

// 构造前 k 个最大元素小顶堆,取堆顶
// 从数组中取出 k 个元素构造一个小顶堆,然后将其余元素与小顶堆对比,如果大于堆顶则替换堆顶,然后堆化,所有元素遍历完成后,堆中的堆顶即为第 k 个最大值
var findKthLargest = function (nums, k) {
    let heap = [,], i = 0
    while (i < k) {
        heap.push(nums[i++])
    }
    buildHeap(heap, k)

    for (let i = k; i < nums.length; i++) {
        if (heap[1] < nums[i]) {
            heap[1] = nums[i]
            heapify(heap, k, 1)
        }
    }
    return heap[1]
};

let buildHeap = (arr, k) => {
    if (k === 1) return
    for (let i = Math.floor(k/2); i>=1; i--) {
        heapify(arr, k, i)
    }
}

let heapify = (arr, k, i) => {
    while(true) {
        let minIndex = i
        if (2*i <= k && arr[2*i] < arr[i]) {
            minIndex = 2*i
        }
        if (2*i+1 <= k && arr[2*i+1] <arr[minIndex]) {
            minIndex = 2*i + 1
        }
        if (minIndex !== i) {
            swap(arr, i, minIndex)
            i = minIndex
        } else {
            break
        }
    }
}

let swap = (arr, i, j) => {
    let temp = arr[i]
    arr[i] = arr[j]
    arr[j] = temp
}

557. 反转字符串中的单词 III

557. 反转字符串中的单词 III

Description

Difficulty: 简单

Related Topics: 双指针, 字符串

给定一个字符串 s ,你需要反转字符串中每个单词的字符顺序,同时仍保留空格和单词的初始顺序。

示例 1:

输入:s = "Let's take LeetCode contest"
输出:"s'teL ekat edoCteeL tsetnoc"

示例 2:

输入: s = "God Ding"
输出:"doG gniD"

提示:

  • 1 <= s.length <= 5 * 104
  • s 包含可打印的 ASCII 字符。
  • s 不包含任何开头或结尾空格。
  • s 里 至少 有一个词。
  • s 中的所有单词都用一个空格隔开。

Solution

Language: JavaScript

/**
 * @param {string} s
 * @return {string}
 */
var reverseWords = function(s) {
    return s.split(' ').map(item => {
        return item.split('').reverse().join('')
    }).join(' ')
};

121. 买卖股票的最佳时机

121. 买卖股票的最佳时机

Description

Difficulty: 简单

Related Topics: 数组, 动态规划

给定一个数组 prices ,它的第 i 个元素 prices[i] 表示一支给定股票第 i 天的价格。

你只能选择 某一天 买入这只股票,并选择在 未来的某一个不同的日子 卖出该股票。设计一个算法来计算你所能获取的最大利润。

返回你可以从这笔交易中获取的最大利润。如果你不能获取任何利润,返回 0

示例 1:

输入:[7,1,5,3,6,4]
输出:5
解释:在第 2 天(股票价格 = 1)的时候买入,在第 5 天(股票价格 = 6)的时候卖出,最大利润 = 6-1 = 5 。
     注意利润不能是 7-1 = 6, 因为卖出价格需要大于买入价格;同时,你不能在买入前卖出股票。

示例 2:

输入:prices = [7,6,4,3,1]
输出:0
解释:在这种情况下, 没有交易完成, 所以最大利润为 0。

提示:

  • 1 <= prices.length <= 105
  • 0 <= prices[i] <= 104

Solution

Language: JavaScript

/**
 * @param {number[]} prices
 * @return {number}
 */
// 买入卖出各一次
//  贪心
// var maxProfit = function(prices) {
//     if (prices.length === 0) return 0

//     let min = prices[0]
//     let max = 0

//     for (let p of prices) {
//         min = Math.min(min, p)
//         max = Math.max(max, p - min)
//     }

//     return max
// }

// 动态规划 时间复杂度O(n) 空间复杂度O(n),dp数组第二维是常数
var maxProfit = function(prices) {
    let n = prices.length
    let dp = new Array(n).fill(0).map(() => new Array(2));

    dp[0][0] = 0
    dp[0][1] = -prices[0]

    for (let i = 1; i < n; i++) {
        dp[i][0] = Math.max(dp[i-1][0], dp[i-1][1] + prices[i])
        dp[i][1] = Math.max(dp[i-1][1], - prices[i])
    }

    return dp[n-1][0]
}

// 压缩空间
// var maxProfit = function(prices) {
//     let n = prices.length
//     let dp = Array.from(new Array(n), () => new Array(2))

//     dp[0] = 0
//     dp[1] = -prices[0]

//     for (let i = 1; i < n; i++) {
//         dp[0] = Math.max(dp[0], dp[1] + prices[i])
//         dp[1] = Math.max(dp[1], -prices[i])
//     }
//     return dp[0]
// }

237. 删除链表中的节点

237. 删除链表中的节点

Description

Difficulty: 中等

Related Topics: 链表

有一个单链表的 head,我们想删除它其中的一个节点 node

给你一个需要删除的节点 node 。你将 无法访问 第一个节点  head

链表的所有值都是 唯一的,并且保证给定的节点 node 不是链表中的最后一个节点。

删除给定的节点。注意,删除节点并不是指从内存中删除它。这里的意思是:

  • 给定节点的值不应该存在于链表中。
  • 链表中的节点数应该减少 1。
  • node 前面的所有值顺序相同。
  • node 后面的所有值顺序相同。

自定义测试:

  • 对于输入,你应该提供整个链表 head 和要给出的节点 nodenode 不应该是链表的最后一个节点,而应该是链表中的一个实际节点。
  • 我们将构建链表,并将节点传递给你的函数。
  • 输出将是调用你函数后的整个链表。

示例 1:

输入:head = [4,5,1,9], node = 5
输出:[4,1,9]
解释:指定链表中值为 5 的第二个节点,那么在调用了你的函数之后,该链表应变为 4 -> 1 -> 9

示例 2:

输入:head = [4,5,1,9], node = 1
输出:[4,5,9]
解释:指定链表中值为 1 的第三个节点,那么在调用了你的函数之后,该链表应变为 4 -> 5 -> 9

提示:

  • 链表中节点的数目范围是 [2, 1000]
  • -1000 <= Node.val <= 1000
  • 链表中每个节点的值都是 唯一
  • 需要删除的节点 node链表中的节点 ,且 不是末尾节点

Solution

Language: JavaScript

/**
 * Definition for singly-linked list.
 * function ListNode(val) {
 *     this.val = val;
 *     this.next = null;
 * }
 */
/**
 * @param {ListNode} node
 * @return {void} Do not return anything, modify node in-place instead.
 */
// 和下一个节点交换
var deleteNode = function(node) {
    node.val = node.next.val
    node.next = node.next.next
};

230. 二叉搜索树中第K小的元素

230. 二叉搜索树中第K小的元素

Description

Difficulty: 中等

Related Topics: , 深度优先搜索, 二叉搜索树, 二叉树

给定一个二叉搜索树的根节点 root ,和一个整数 k ,请你设计一个算法查找其中第 k个最小元素(从 1 开始计数)。

示例 1:

输入:root = [3,1,4,null,2], k = 1
输出:1

示例 2:

输入:root = [5,3,6,2,4,null,null,1], k = 3
输出:3

提示:

  • 树中的节点数为 n
  • 1 <= k <= n <= 104
  • 0 <= Node.val <= 104

**进阶:**如果二叉搜索树经常被修改(插入/删除操作)并且你需要频繁地查找第 k 小的值,你将如何优化算法?

Solution

Language: JavaScript

/**
 * Definition for a binary tree node.
 * function TreeNode(val, left, right) {
 *     this.val = (val===undefined ? 0 : val)
 *     this.left = (left===undefined ? null : left)
 *     this.right = (right===undefined ? null : right)
 * }
 */
/**
 * @param {TreeNode} root
 * @param {number} k
 * @return {number}
 */
var kthSmallest = function (root, k) {
    let res
    let count = 0
    function traversal(node) {
        if (node !== null) {
            if (count < k) traversal(node.left)
            if (++count === k) res = node.val
            if (count < k) traversal(node.right)
        }
    }
    traversal(root)
    return res
}
// var kthSmallest = function(root, k) {
//     let arr = []
//     function traversal (node) {
//         if (node !== null && arr.length < k) {
//             traversal(node.left)
//             arr.push(node.val)
//             traversal(node.right)
//         }
//     }
//     traversal(root)
//     return arr[k-1]
// };

217. 存在重复元素

217. 存在重复元素

Description

Difficulty: 简单

Related Topics: 数组, 哈希表, 排序

给你一个整数数组 nums 。如果任一值在数组中出现 至少两次 ,返回 true ;如果数组中每个元素互不相同,返回 false

示例 1:

输入:nums = [1,2,3,1]
输出:true

示例 2:

输入:nums = [1,2,3,4]
输出:false

示例 3:

输入:nums = [1,1,1,3,3,4,3,2,4,2]
输出:true

提示:

  • 1 <= nums.length <= 105
  • -109 <= nums[i] <= 109

Solution

Language: JavaScript

/**
 * @param {number[]} nums
 * @return {boolean}
 */
// 排序
// var containsDuplicate = function(nums) {
//     nums.sort((a, b) => a - b)
//     const n = nums.length
//     for (let i = 0; i < n - 1; i++) {
//         if (nums[i] === nums[i + 1]) {
//             return true
//         }
//     }
//     return false
// };


// 哈希表
var containsDuplicate = function(nums) {
    const set = new Set()
    for (let x of nums) {
        if (set.has(x)) return true
        set.add(x)
    }
    return false
};

2. 两数相加

2. 两数相加

Description

Difficulty: 中等

Related Topics: 递归, 链表, 数学

给你两个 非空 的链表,表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的,并且每个节点只能存储 一位 数字。

请你将两个数相加,并以相同形式返回一个表示和的链表。

你可以假设除了数字 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]

提示:

  • 每个链表中的节点数在范围 [1, 100]
  • 0 <= Node.val <= 9
  • 题目数据保证列表表示的数字不含前导零

Solution

Language: JavaScript

/**
 * 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 dummy = new ListNode()
    let curr = dummy
    let carry = 0

    while (l1 || l2) {
        const x = l1 ? l1.val : 0
        const y = l2 ? l2.val : 0

        const total = x + y + carry
        curr.next = new ListNode(total % 10)
        curr = curr.next
        carry = Math.floor(total / 10)

        if (l1) l1 = l1.next
        if (l2) l2 = l2.next
    }
    if (carry) curr.next = new ListNode(carry)

    return dummy.next
};

236. 二叉树的最近公共祖先

236. 二叉树的最近公共祖先

Description

Difficulty: 中等

Related Topics: , 深度优先搜索, 二叉树

给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。

中最近公共祖先的定义为:“对于有根树 T 的两个节点 p、q,最近公共祖先表示为一个节点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。”

示例 1:

输入:root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 1
输出:3
解释:节点 5 和节点 1 的最近公共祖先是节点 3 。

示例 2:

输入:root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 4
输出:5
解释:节点 5 和节点 4 的最近公共祖先是节点 5 。因为根据定义最近公共祖先节点可以为节点本身。

示例 3:

输入:root = [1,2], p = 1, q = 2
输出:1

提示:

  • 树中节点数目在范围 [2, 105] 内。
  • -109 <= Node.val <= 109
  • 所有 Node.val 互不相同
  • p != q
  • pq 均存在于给定的二叉树中。

Solution

Language: JavaScript

/**
 * Definition for a binary tree node.
 * function TreeNode(val) {
 *     this.val = val;
 *     this.left = this.right = null;
 * }
 */
/**
 * @param {TreeNode} root
 * @param {TreeNode} p
 * @param {TreeNode} q
 * @return {TreeNode}
 */
// 递归
var lowestCommonAncestor = function(root, p, q) {
    if (root === null || root === p || root === q) {
        return root
    }

    const left = lowestCommonAncestor(root.left, p, q)
    const right = lowestCommonAncestor(root.right, p, q)

    if (left === null) return right
    if (right === null) return left

    return root
};

136. 只出现一次的数字

136. 只出现一次的数字

Description

Difficulty: 简单

Related Topics: 位运算, 数组

给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。

说明:

你的算法应该具有线性时间复杂度。 你可以不使用额外空间来实现吗?

示例 1:

输入: [2,2,1]
输出: 1

示例 2:

输入: [4,1,2,1,2]
输出: 4

Solution

Language: JavaScript

/**
 * @param {number[]} nums
 * @return {number}
 */
// var singleNumber = function(nums) {
//     let ans = 0;
//     for(const num of nums) {
//         ans ^= num;
//     }
//     return ans;
// };

var singleNumber = function(nums) {
    return nums.reduce((pre, cur) => {
        return pre ^ cur;
    }, 0)
}

141. 环形链表

141. 环形链表

Description

Difficulty: 简单

Related Topics: 哈希表, 链表, 双指针

给你一个链表的头节点 head ,判断链表中是否有环。

如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。**注意:pos 不作为参数进行传递 **。仅仅是为了标识链表的实际情况。

如果链表中存在环 ,则返回 true 。 否则,返回 false

示例 1:

输入:head = [3,2,0,-4], pos = 1
输出:true
解释:链表中有一个环,其尾部连接到第二个节点。

示例 2:

输入:head = [1,2], pos = 0
输出:true
解释:链表中有一个环,其尾部连接到第一个节点。

示例 3:

输入:head = [1], pos = -1
输出:false
解释:链表中没有环。

提示:

  • 链表中节点的数目范围是 [0, 104]
  • -105 <= Node.val <= 105
  • pos-1 或者链表中的一个 有效索引

**进阶:**你能用 O(1)(即,常量)内存解决此问题吗?

Solution

Language: JavaScript

/**
 * Definition for singly-linked list.
 * function ListNode(val) {
 *     this.val = val;
 *     this.next = null;
 * }
 */

/**
 * @param {ListNode} head
 * @return {boolean}
 */
// 快慢指针
// 快慢指针初始化指向 head
// 快指针走到末尾时停止
// 慢指针走一步,快指针走两步
// 快慢指针相遇,说明含有环,否则不含有环
var hasCycle = function(head) {
    let slow = head
    let fast = head
    while (fast && fast.next) {
        slow = slow.next
        fast = fast.next.next
        if (slow === fast) {
            return true
        }
    }
    return false
}

// 哈希表
// var hasCycle = function(head) {
//     const map = new Map()
//     let p = head
//     while (p) {
//         if (map.get(p)) return true
//         else {
//             map.set(p, p.val)
//             p = p.next
//         }
//     }
//     return false
// }

70. 爬楼梯

70. 爬楼梯

Description

Difficulty: 简单

Related Topics: 记忆化搜索, 数学, 动态规划

假设你正在爬楼梯。需要 n 阶你才能到达楼顶。

每次你可以爬 12 个台阶。你有多少种不同的方法可以爬到楼顶呢?

示例 1:

输入:n = 2
输出:2
解释:有两种方法可以爬到楼顶。
1\. 1 阶 + 1 阶
2\. 2 阶

示例 2:

输入:n = 3
输出:3
解释:有三种方法可以爬到楼顶。
1\. 1 阶 + 1 阶 + 1 阶
2\. 1 阶 + 2 阶
3\. 2 阶 + 1 阶

提示:

  • 1 <= n <= 45

Solution

Language: JavaScript

/**
 * @param {number} n
 * @return {number}
 * 题目分析:
 * 第1级台阶:1种方法(爬1级)
 * 第2级台阶:2种方法(爬1级或爬2级)
 * 第n级台阶:dp[i] = dp[i-1] + dp[i-2]
 */
// 动态规划
// 滚动数组**
// var climbStairs = function(n) {
//     if (n === 1) return 1
//     if (n === 2) return 2
//     let [pre, cur, sum] = [1, 1, 2]
//     for (let i = 3; i <= n; i++) {
//         [pre, cur] = [cur, sum]
//         sum = pre + cur
//     }
//     return sum
// }

var climbStairs = function(n) {
    const dp = []
    dp[0] = 1
    dp[1] = 1
    for (let i = 2; i <= n; i++) {
        dp[i] = dp[i-1] + dp[i-2]
    }
    return dp[n]
}

104. 二叉树的最大深度

104. 二叉树的最大深度

Description

Difficulty: 简单

Related Topics: , 深度优先搜索, 广度优先搜索, 二叉树

给定一个二叉树,找出其最大深度。

二叉树的深度为根节点到最远叶子节点的最长路径上的节点数。

说明: 叶子节点是指没有子节点的节点。

示例:
给定二叉树 [3,9,20,null,null,15,7]

    3
   / \
  9  20
    /  \
   15   7

返回它的最大深度 3 。

Solution

Language: JavaScript

/**
 * Definition for a binary tree node.
 * function TreeNode(val, left, right) {
 *     this.val = (val===undefined ? 0 : val)
 *     this.left = (left===undefined ? null : left)
 *     this.right = (right===undefined ? null : right)
 * }
 */
/**
 * @param {TreeNode} root
 * @return {number}
 */
var maxDepth = function(root) {
    let res = 0
    function traversal (root, depth) {
        if (root) {
            if (depth > res) {
                res = depth
            }
            if (root.left) {
                traversal (root.left, depth + 1)
            }
            if (root.right) {
                traversal (root.right, depth + 1)
            }
        }
    }
    traversal(root, 1)
    return res
};

23. 合并K个升序链表

23. 合并K个升序链表

Description

Difficulty: 困难

Related Topics: 链表, 分治, 堆(优先队列), 归并排序

给你一个链表数组,每个链表都已经按升序排列。

请你将所有链表合并到一个升序链表中,返回合并后的链表。

示例 1:

输入:lists = [[1,4,5],[1,3,4],[2,6]]
输出:[1,1,2,3,4,4,5,6]
解释:链表数组如下:
[
  1->4->5,
  1->3->4,
  2->6
]
将它们合并到一个有序链表中得到。
1->1->2->3->4->4->5->6

示例 2:

输入:lists = []
输出:[]

示例 3:

输入:lists = [[]]
输出:[]

提示:

  • k == lists.length
  • 0 <= k <= 10^4
  • 0 <= lists[i].length <= 500
  • -10^4 <= lists[i][j] <= 10^4
  • lists[i]升序 排列
  • lists[i].length 的总和不超过 10^4

Solution

Language: JavaScript

/**
 * Definition for singly-linked list.
 * function ListNode(val, next) {
 *     this.val = (val===undefined ? 0 : val)
 *     this.next = (next===undefined ? null : next)
 * }
 */
/**
 * @param {ListNode[]} lists
 * @return {ListNode}
 * 递归合并链表+两两合并
 */
var mergeKLists = function(lists) {
    if (!lists.length) return null
    function merge(l1, l2) {
        if (!l1) return l2
        if (!l2) return l1
        if (l1.val < l2.val) {
            l1.next = merge(l1.next, l2)
            return l1
        } else {
            l2.next = merge(l1, l2.next)
            return l2
        }
    }
    return lists.reduce((pre, cur) => merge(pre, cur))
}

7. 整数反转

7. 整数反转

Description

Difficulty: 中等

Related Topics: 数学

给你一个 32 位的有符号整数 x ,返回将 x 中的数字部分反转后的结果。

如果反转后整数超过 32 位的有符号整数的范围 [−231,  231 − 1] ,就返回 0。

假设环境不允许存储 64 位整数(有符号或无符号)。

示例 1:

输入:x = 123
输出:321

示例 2:

输入:x = -123
输出:-321

示例 3:

输入:x = 120
输出:21

示例 4:

输入:x = 0
输出:0

提示:

  • -231 <= x <= 231 - 1

Solution

Language: JavaScript

/**
 * @param {number} x
 * @return {number}
 */
var reverse = function(x) {
    let result = 0

    while(x) {
        result = result * 10 + x % 10
        x = x / 10 | 0
    }

    return (result | 0) === result ? result : 0
};

54. 螺旋矩阵

54. 螺旋矩阵

Description

Difficulty: 中等

Related Topics: 数组, 矩阵, 模拟

给你一个 mn 列的矩阵 matrix ,请按照 顺时针螺旋顺序 ,返回矩阵中的所有元素。

示例 1:

输入:matrix = [[1,2,3],[4,5,6],[7,8,9]]
输出:[1,2,3,6,9,8,7,4,5]

示例 2:

输入:matrix = [[1,2,3,4],[5,6,7,8],[9,10,11,12]]
输出:[1,2,3,4,8,12,11,10,9,5,6,7]

提示:

  • m == matrix.length
  • n == matrix[i].length
  • 1 <= m, n <= 10
  • -100 <= matrix[i][j] <= 100

Solution

Language: JavaScript

/**
 * @param {number[][]} matrix
 * @return {number[]}
 */
var spiralOrder = function(matrix) {
    let n = []
    while (matrix.length) {
        n = _.concat(n, matrix.shift())
        matrix = _.reverse(_.zip(...matrix))
    }
    return n
};

59. 螺旋矩阵 II

59. 螺旋矩阵 II

Description

Difficulty: 中等

Related Topics: 数组, 矩阵, 模拟

给你一个正整数 n ,生成一个包含 1 到 n2 所有元素,且元素按顺时针顺序螺旋排列的 n x n 正方形矩阵 matrix

示例 1:

输入:n = 3
输出:[[1,2,3],[8,9,4],[7,6,5]]

示例 2:

输入:n = 1
输出:[[1]]

提示:

  • 1 <= n <= 20

Solution

Language: JavaScript

/**
 * @param {number} n
 * @return {number[][]}
 */
var generateMatrix = function(n) {
    let left = 0
    let right = n - 1
    let bottom = n - 1
    let top = 0
    const total = n * n

    const dep = []

    for (let i = 0; i < n; i++) {
        dep[i] = []
    }

    let count = 0

    while (count < total) {
        for (let i = left; i <= right; i++) dep[left][i] = ++count
        top++
        for (let i = top; i <= bottom; i++) dep[i][right] = ++count
        right--
        for (let i = right; i >= left; i--) dep[bottom][i] = ++count
        bottom--
        for (let i = bottom; i >= top; i--) dep[i][left] = ++count
        left++
    }

    return dep
};

292. Nim 游戏

292. Nim 游戏

Description

Difficulty: 简单

Related Topics: 脑筋急转弯, 数学, 博弈

你和你的朋友,两个人一起玩 :

  • 桌子上有一堆石头。
  • 你们轮流进行自己的回合, **你作为先手 **。
  • 每一回合,轮到的人拿掉 1 - 3 块石头。
  • 拿掉最后一块石头的人就是获胜者。

假设你们每一步都是最优解。请编写一个函数,来判断你是否可以在给定石头数量为 n 的情况下赢得游戏。如果可以赢,返回 true;否则,返回 false

示例 1:

输入:n = 4
输出:false 
解释:以下是可能的结果:
1\. 移除1颗石头。你的朋友移走了3块石头,包括最后一块。你的朋友赢了。
2\. 移除2个石子。你的朋友移走2块石头,包括最后一块。你的朋友赢了。
3.你移走3颗石子。你的朋友移走了最后一块石头。你的朋友赢了。
在所有结果中,你的朋友是赢家。

示例 2:

输入:n = 1
输出:true

示例 3:

输入:n = 2
输出:true

提示:

  • 1 <= n <= 231 - 1

Solution

Language: JavaScript

/**
 * @param {number} n
 * @return {boolean}
 */
// 数学推理: 4块永远输,那么4的倍数一定输
var canWinNim = function(n) {
    return n % 4 !== 0;
};

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.