1. 两数之和
给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那 两个 整数,并返回它们的数组下标。
你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。
你可以按任意顺序返回答案。
输入:nums = [2,7,11,15], target = 9
输出:[0,1]
解释:因为 nums[0] + nums[1] == 9 ,返回 [0, 1] 。
var twoSum = function(nums, target) {
let p = new Map();
for (let i = 0; i < nums.length; i++) {
let m = nums[i];
let n = target - n;
if (p.has(n)) {
return [p.get(n), i]
}
p.set(m, i)
}
};
20. 有效的括号
给定一个只包括 '(',')','{','}','[',']' 的字符串 s ,判断字符串是否有效。
有效字符串需满足:
左括号必须用相同类型的右括号闭合。
左括号必须以正确的顺序闭合。
每个右括号都有一个对应的相同类型的左括号。
输入: s = "()"
输出: true
var isValid = function(s) {
let ss = [];
for (let i = 0; i < s.length; s++) {
switch (s[i]) {
case '(':
case '[':
case '[':
ss.push(s[i]);
break;
case ')':
if (ss.length !== 0 || ss[ss.length-1] !== '(') {
return false
}
ss.pop();
break;
case ']':
if (ss.length !== 0 || ss[ss.length-1] !== '[') {
return false
}
ss.pop();
break
case '}':
if (ss.length !== 0 || ss[ss.length-1] !== '{') {
return false
}
ss.pop();
break
}
}
return ss.length == 0
}
21. 合并两个有序列表
将两个升序链表合并为一个新的 **升序** 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。
输入: l1 = [1,2,4], l2 = [1,3,4]
输出: [1,1,2,3,4,4]
定义一个虚拟头节点dummy,依次比较l1和l2链表值的大小,依次放到dummy上
var mergeTwoLists = function(list1, list2) {
let dummy = new ListNode();
let p = dummy;
while(list1 != null && list2 != null) {
if (list1.val >= list2.val) {
p.next = list2;
list2 = list2.next
} else {
p.next = list1;
list1 = list1.next;
}
p = p.next;
}
if (list1 != null) {
p.next = list1
}
if (list2 != null) {
p.next = list2
}
return dummy.next
}
70. 爬楼梯
假设你正在爬楼梯。需要 `n` 阶你才能到达楼顶。
每次你可以爬 `1` 或 `2` 个台阶。你有多少种不同的方法可以爬到楼顶呢?
动态规划:
递推公式:dp[i] = dp[i-1] + dp[i-1]
dp[i] 表示爬到第i层楼梯的迈法总数
dp[i-1] 前一个楼梯的总数,正好到i迈一步
dp[i-2] 前两个楼梯的总数,正好到i迈两步
var climbStairs = function (n) {
if (n == 1) return 1;
if (n == 2) return 2;
let dp = new Array(n).fill(0);
dp[0] = 1;
dp[1] = 2;
for (let i = 2; i < n; i++) {
dp[i] = dp[i-1] + dp[i-2]
}
return dp[n-1]
}
94. 二叉树的中序遍历
给定一个二叉树的根节点 `root` ,返回 *它的 **中序** 遍历* 。
let inorderTraversal = function (root) {
const res = [];
let reaset = function (root) {
if (!root) return null
reaset(root.left);
res.push(root.val);
reaset(root.right);
}
reaset(root);
return res
}
101. 对称二叉树
你一个二叉树的根节点 `root` , 检查它是否轴对称。
var isSymmetric = function (root) {
if (root == null || (root.left == null && root.right == null)) return true;
const exam = function (lNode, rNode) {
if (lNode === null && rNode === null) return true
if (lNode === null || rNode === null || lNode.val !== rNode.val) return false;
return exam(lNode.left, rNode.right) && exam(lNode.right, rNode.left)
}
return exam(root.left, root.right)
}
104. 二叉树的最大深度
给定一个二叉树,找出其最大深度。
二叉树的深度为根节点到最远叶子节点的最长路径上的节点数。
var maxDepth = function (root) {
if (root === null) {
return 0
}
let leftDepth = maxDepth(root.left)
let rightDepth = maxDepth(root.right)
return Math.max(leftDepth, rightDepth) + 1
}
136. 只出现一次的数字
给定一个**非空**整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。
使用异或运算⊕,异或运算有如下特性:
1. 任何数和0做异或运算,结果仍然是原来的数: a ⊕ 0 = a
2. 任何数和自身做异或运算,结果是0: a ⊕ a = 0
var singleNumber = function(nums) {
let ans = 0;
for (let p of nums) {
ans ^= p
}
return ans
};
141. 环形链表
给你一个链表的头节点 head ,判断链表中是否有环。
如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。注意:pos 不作为参数进行传递 。仅仅是为了标识链表的实际情况。
如果链表中存在环 ,则返回 true 。 否则,返回 false 。
使用快慢指针,快指针走两步,慢指针走一步,在快指针走完前,快慢指针相等则成环
var hasCycle = function(head) {
let slow = head;
let fast = head;
while(fast != null && fast.next != null) {
slow = slow.next;
fast = fast.next.next;
if (slow == fast) {
return true
}
}
return false
};
160. 相交链表
给你两个单链表的头节点 `headA` 和 `headB` ,请你找出并返回两个单链表相交的起始节点。如果两个链表不存在相交节点,返回 `null` 。
使用两个指针p1和p2分别在两条链表上前进,可以让p1遍历完链表A后再继续遍历链表B,让p2遍历完链表B后再继续遍历链表A,这样进行拼接,可以让p1和p2同时进入公共部分,也就是相交节点c
var getIntersectionNode = function(headA, headB) {
let p1 = headA;
let p2 = headB;
while(p1 !== p1) {
if (p1 == null) {
p1 = headB
} else {
p1 = p1.next
}
if (p2 == null) {
p2 = headA
} else {
p2 = p2.next
}
}
return p1
}
169. 多数元素
给定一个大小为 n 的数组 nums ,返回其中的多数元素。多数元素是指在数组中出现次数 大于 ⌊ n/2 ⌋ 的元素。
你可以假设数组是非空的,并且给定的数组总是存在多数元素。
解法一:使用hash表,记录每个元素出现的次数,然后寻找出现次数最多的那个元素
解法二:题目说了这个目标元素出现的次数过半,如果把这个众数元素想象成正点粒子,其他的所有元素都想象成负数粒子,在正负粒子混合的过程中,整体的带电性可能在正负间波动,但最终结果一定是正电
var majorityElement = function(nums) {
let target = 0
let count = 0
for (let i = 0; i < nums.length; i++) {
if (count == 0) {
target = nums[i];
count = 1;
} else if (nums[i] == target) {
count++
} else {
count--
}
}
return target
}
206. 反转链表
给你单链表的头节点 `head` ,请你反转链表,并返回反转后的链表。
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
}
226. 翻转二叉树
给你一棵二叉树的根节点 `root` ,翻转这棵二叉树,并返回其根节点。
var invertTree = function(root) {
traverse(root);
return root
};
var traverse = function(root) {
if (root == null) return
let temp = root.left;
root.left = root.right;
root.right = temp;
traverse(root.right);
traverse(root.left)
}
234. 回文链表
给你一个单链表的头节点 `head` ,请你判断该链表是否为回文链表。如果是,返回 `true` ;否则,返回 `false` 。
1. 首先使用快慢指针找到链表中点,如果fast指针没有指向null,说明链表长度为奇数slow还需要再走一步
2. 反转慢指针链表,得到对称右边
3. 对比左右链表,判断是否相同
var isPalindrome = function(head) {
let fast = head;
let slow = head;
while(fast != null && fast.next != null) {
slow = slow.next;
fast = fast.next.next;
}
if (fast != null) {
slow = slow.next;
}
let right = reserve(slow);
let left = head;
while(right != null) {
if (left.val !== right.val) {
return false
}
left = left.next;
right = right.next
}
return true
}
var reserve = function(root) {
let prev = null;
let curr = head;
while(curr) {
let now = curr.next;
curr.next = prev;
prev = curr;
curr = now
}
return prev
}
283. 移动零
给定一个数组 `nums`,编写一个函数将所有 `0` 移动到数组的末尾,同时保持非零元素的相对顺序。
**请注意** ,必须在不复制数组的情况下原地对数组进行操作。
先移除所有0,然后把最后的元素都置为0
var moveZeroes = function(nums) {
let index = 0;
for (let i = 0; i < nums.length; i++) {
if(nums[i] != 0) {
nums[index] = nums[i]
index++
}
}
while(index < nums.length) {
nums[index] = 0
index++
}
}
543. 二叉树的最大直径
给定一棵二叉树,你需要计算它的直径长度。一棵二叉树的直径长度是任意两个结点路径长度中的最大值。这条路径可能穿过也可能不穿过根结点。
二叉树的最大直径,就是左右子树的最大深度之和,最直接的想法就是对每个节点计算左右子树的最大高度,得出每个节点的直径,从而得出最大的直径
var diameterOfBinaryTree = function(root) {
let res = 0;
function depth(root) {
if (!root) return 0
const leftHeight = depth(root.left);
const rightHeight = depth(root.right);
res = Math.max(leftHeight+rightHeight, res);
return 1+Math.max(leftHeight, rightHeight)
}
depth(root)
return res
};
617. 合并二叉树
给你两棵二叉树: `root1` 和 `root2` 。
想象一下,当你将其中一棵覆盖到另一棵之上时,两棵树上的一些节点将会重叠(而另一些不会)。你需要将这两棵树合并成一棵新二叉树。合并的规则是:如果两个节点重叠,那么将这两个节点的值相加作为合并后节点的新值;否则,不为 null 的节点将直接作为新二叉树的节点。
返回合并后的二叉树。
var mergeTrees = function(root1, root2) {
if (root1 == null) {
return root2
}
if (root2 == null) {
return root1
}
root1.val+=root2.val;
root1.left = mergeTrees(root1.left, root2.left);
root1.right = mergeTrees(root1.right, root2.right);
return root1
}