leetcode Easy

85 阅读7分钟

1. 两数之和

给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target  的那 两个 整数,并返回它们的数组下标。
你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。
你可以按任意顺序返回答案。
输入:nums = [2,7,11,15], target = 9
输出:[0,1]
解释:因为 nums[0] + nums[1] == 9 ,返回 [0, 1] 。
// 使用hash表复制判断,对于一个元素nums[i],想知道有没有另一个元素num[j]的值为target-nums[i],我们用一个hash表记录每个元素的值到索引的映射,这样就能快速的判断数组中是否有一个值为target-nums[i]的元素了
/** * @param {number[]} nums 
    * @param {number} target 
    * @return {number[]} */ 
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
/**
 * @param {string} s
 * @return {boolean}
 */
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上
/**
 * @param {ListNode} list1
 * @param {ListNode} list2
 * @return {ListNode}
 */
 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
/**
 * @param {number[]} nums
 * @return {number}
 */
var singleNumber = function(nums) {
    let ans = 0;
    for (let p of nums) {
        ans ^= p
    }
    return ans
};

141. 环形链表

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

如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。注意:pos 不作为参数进行传递 。仅仅是为了标识链表的实际情况。
如果链表中存在环 ,则返回 true 。 否则,返回 false
使用快慢指针,快指针走两步,慢指针走一步,在快指针走完前,快慢指针相等则成环
/**
 * @param {ListNode} head
 * @return {boolean}
 */
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) {
            // 当计数器为0时,假设nums[i]为众数
            target = nums[i];
            // 众数出现一次
            count = 1;
        } else if (nums[i] == target) {
            // 遇到的是目标众数,计算器加1
            count++
        } else {
            // 遇到的不是目标众数,计算器减1
            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
}