Leetcode 热门题目100道每日一题

 1.检索物品数量   

/**
 * @param {string[][]} items
 * @param {string} ruleKey
 * @param {string} ruleValue
 * @return {number}
 */
var countMatches = function(items, ruleKey, ruleValue) {
    let resSum=0
    const ruleValueArr=["type","color","name"]
    const index=ruleValueArr.indexOf(ruleKey)
    if(index<0)
    return 0
    for(let item of items){
        if(item[index]==ruleValue)
        resSum++
    }
    return resSum
};

2. 两数之和

/**
 * @param {number[]} nums
 * @param {number} target
 * @return {number[]}
 */
var twoSum = function(nums, target) {
    for(let i=0,len=nums.length;i<len;i++){
        let findingNum=target-nums[i]
        if(nums.indexOf(findingNum)>=0&&nums.indexOf(findingNum)!==i){
            return [i,nums.indexOf(findingNum)].sort((a,b)=>a-b)
        }
    }
    return []
};

3. 两数相加

当时第一反应想到的解法

/**
 * 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) {
      function reverseList(head) {
        let cur = head
        let pre = null
        let res = ""
        while (cur != null) {
            const next = cur.next
            cur.next = pre
            pre = cur
            cur = next
        }
        while (pre != null) {
            res = res + pre.val
            pre = pre.next
        }
        return res
    }
    let res1 = reverseList(l1)
    let res2 = reverseList(l2)
    let res3 = (Number(res1) + Number(res2)).toString().split("").reverse()
    let resL = new ListNode()
    let cur = resL
    for (let i = 0; i < res3.length; i++) {
        cur.next = new ListNode(res3[i])
        cur = cur.next
    }
    return resL.next
};

就是翻转链表获取参数然后数字相加,但是发现了最后两题过不去,数字范围太大超过最大值导致返回NaN了。

 后来想到 应该可以直接链表相加。满10进1

/**
 * 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 cur1 = l1
    let cur2 = l2
    let carry = 0
    let res = new ListNode()
    let resCur = res
    while (cur1 && cur2) {
        let tempRes = cur1.val + cur2.val + carry
        resCur.next = new ListNode(tempRes % 10)
        carry = Math.floor(tempRes / 10)
        cur1 = cur1.next
        cur2 = cur2.next
        resCur = resCur.next
    }
    while (cur1) {
        let tempRes = cur1.val + carry
        resCur.next = new ListNode(tempRes % 10)
        carry = Math.floor(tempRes / 10)
        cur1 = cur1.next
        resCur = resCur.next
    }
    while (cur2) {
        let tempRes = cur2.val + carry
        resCur.next = new ListNode(tempRes % 10)
        carry = Math.floor(tempRes / 10)
        cur2 = cur2.next
        resCur = resCur.next
    }
    if (carry > 0) {
        resCur.next = new ListNode(carry)
    }
    return res.next;
};

4. 最长回文子串

 第一反应解法

时间复杂度太高了,她测试用例居然输入了那么长的字符串

/**
 * @param {string} s
 * @return {string}
 */
var longestPalindrome = function(s) {
   //双指针法
    let p1 = 0
    let res = ""
    while (p1 < s.length) {
        let p2 = p1
        while (p2 < s.length) {
            let target = s.slice(p1, p2 + 1)
            if (target === target.split("").reverse().join("")) {
                res = res.length > target.length ? res : target
            }
            p2++
        }
        p1++
    }
    return res
};

第二反应采用的是中心扩散的方法 就是以一个字符为中心左右移动开始指针和结束指针,判断是否回文。

/**
 * @param {string} s
 * @return {string}
 */
var longestPalindrome = function (s) {
    //中心扩散 中心指针
    //回文的几种基本情况
    /**
     * @type 仅自身回文  “a”
     * @type 偶数回文 “abba”
     * @type 中心对称奇数回文 “aba”
     */
    let res = ""
    for (let len = s.length, i = 0; i < len; i++) {
        getResString(i, i) //情况1 3 以某元素为中心左右扩展
        getResString(i, i + 1)//情况2 以i和i+1元素为起始左右扩展
    }
    function getResString(left, right) {
        while (left >= 0 && right < s.length) {
            if (s.charAt(left) !== s.charAt(right)) {
                return
            } else {
                let target = s.slice(left, right + 1)
                res = res.length > target.length ? res : target
                left--
                right++
            }
        }
    }
    return res
};

5. 正则匹配

第一眼看完只能说是没什么思路。思考了一会:直接看答案

/**
 * @type .表示任意字符  *表示前面的单个字符任意数目重复
 * @param {string} s 字符串
 * @param {string} p  字符规律
 * @return {boolean}
 */
var isMatch = function (s, p) {
    //从左向右扫描的话 *的出现会影响结果 改为从右向左扫 把b*看成一个整体进行子集匹配
    if (s == null || p == null) return false;

    const sLen = s.length, pLen = p.length;

    const dp = new Array(sLen + 1);
    for (let i = 0; i < dp.length; i++) {
        dp[i] = new Array(pLen + 1).fill(false); // 将项默认为false
    }
    // base case
    dp[0][0] = true;
    for (let j = 1; j < pLen + 1; j++) {
        if (p[j - 1] == "*") dp[0][j] = dp[0][j - 2];
    }
    // 迭代
    for (let i = 1; i < sLen + 1; i++) {
        for (let j = 1; j < pLen + 1; j++) {

            if (s[i - 1] == p[j - 1] || p[j - 1] == ".") {
                dp[i][j] = dp[i - 1][j - 1];
            } else if (p[j - 1] == "*") {
                if (s[i - 1] == p[j - 2] || p[j - 2] == ".") {
                    dp[i][j] = dp[i][j - 2] || dp[i - 1][j - 2] || dp[i - 1][j];
                } else {
                    dp[i][j] = dp[i][j - 2];
                }
            }
        }
    }
    return dp[sLen][pLen]; // 长sLen的s串 是否匹配 长pLen的p串
}

6. 注水容器

 暴力解法 计算出所有的组合比较大小 肯定超时就不试了,只能想其他的方法:

思路就是 左右指针 左指针如果移动到比上一位小的height 则跳过判断,右指针左移同理。

/**
 * @param {number[]} height
 * @return {number}
 */
var maxArea = function (height) {
    //双指针法
    let maxS = 0
    let i = 0, tempStartMaxHeight = 0
    while (i < height.length - 1) {
        if (height[i] > tempStartMaxHeight) {
            let j = height.length - 1, tempEndMaxHeight = 0
            while (j > i) {
                if (height[j] > tempEndMaxHeight) {
                    let tempS = Math.min(height[i], height[j]) * (j - i)
                    maxS = tempS > maxS ? tempS : maxS
                    tempEndMaxHeight = height[j]
                }
                j--
            }
            tempStartMaxHeight = height[i]
        }
        i++
    }
    return maxS
};

7.三数之和

 猛一看全是思路,细想不暴力解决的话还是有点东西:

自己瞎写的通过了 但是算不上简洁

/**
 * @param {number[]} nums
 * @return {number[][]}
 */
var threeSum = function(nums) {
    let res = []
    let left = nums.filter(item => {
        return item < 0
    })
    let right = nums.filter(item => {
        return item >= 0
    })
    for (let i = 0; i < left.length; i++) {
        for (let j = 0; j < right.length; j++) {
            let target = 0 - left[i] - right[j]
            if (left.indexOf(target, i + 1) !== -1 || right.indexOf(target, j + 1) !== -1) {
                let tempArrStr = [left[i], right[j], target].sort((a, b) => a - b).join("!")
                if (!res.includes(tempArrStr))
                    res.push(tempArrStr)
            }
        }
    }
    res = res.map(item => {
        return item.split("!")
    })
    let zeroNum = 0
    for (let item of right) {
        if (item === 0) {
            zeroNum++
        }
    }
    if (zeroNum >= 3) {
        res.push([0, 0, 0])
    }
    return res
};

8. 电话号码数字组合

 看着一般

回溯法:JS算法之回溯法_js回溯算法_前端小魔女的博客-CSDN博客

/**
 * @param {string} digits
 * @return {string[]}
 */
var letterCombinations = function (digits) {
    let res = []
    if(digits.length===0) return []
    const digitsObj = {
        "1": [],
        "2": ["a", "b", "c"],
        "3": ["d", "e", "f"],
        "4": ["g", "h", "i"],
        "5": ["j", "k", "l"],
        "6": ["m", "n", "o"],
        "7": ["p", "q", "r", "s"],
        "8": ["t", "u", "v"],
        "9": ["w", "x", "y", "z"]
    }
    /**
     * 
     * @param {number} index 当前处理的digits索引 
     * @param {string} path 当前生成的组合 
     */
    function dfs(index, path) {
        if (index === digits.length) res.push(path)
        else if (index < digits.length) {
            for (let item of digitsObj[digits.charAt(index)]) {
                path = path + item
                dfs(index + 1, path)
                path = path.slice(0, path.length - 1)
            }
        }
    }
    dfs(0, [])
    return res
};

9. 删除链表的倒数第n个节点

指针法怼它就完事了

/**
 * 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} n
 * @return {ListNode}
 */
var removeNthFromEnd = function(head, n) {
    let res = new ListNode()
    res.next = head
    let o = res
    let p = head
    let q = head
    for (let i = 0; i < n-1; i++) {
        q = q.next
    }
    while (q.next) {
        o = o.next
        p = p.next
        q = q.next
    }
    o.next = p.next
    return res.next
};

10. 有效括号数

 经典题目 入栈出栈思维就好

/**
 * @param {string} s
 * @return {boolean}
 */
var isValid = function (s) {
    let left = ["(", "[", "{"]
    let tempItems = []
    for (let i = 0; i < s.length; i++) {
        if (left.includes(s.charAt(i))) {
            tempItems.push(s.charAt(i))
        } else if (s.charAt(i) === ")" && tempItems[tempItems.length - 1] === "(") {
            tempItems.pop()
        } else if (s.charAt(i) === "]" && tempItems[tempItems.length - 1] === "[") {
            tempItems.pop()
        } else if (s.charAt(i) === "}" && tempItems[tempItems.length - 1] === "{") {
            tempItems.pop()
        } else {
            return false
        }
    }
    if (tempItems.length === 0) return true
    return false
};

 11. 合并有序链表

经典中的经典了

/**
 * 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) {
    let res=new ListNode()
    let o=res
    while(list1&&list2){
        if(list1.val<list2.val){
            res.next=list1
            list1=list1.next
        }else{
            res.next=list2
            list2=list2.next
        }
        res=res.next
    }
    while(list1){
        res.next=list1
        list1=list1.next
        res=res.next
    }
    while(list2){
        res.next=list2
        list2=list2.next
        res=res.next
    }
    return o.next
};

12. 括号生成

还是回溯法 只不过可以剪枝

    let res = []
    let path = ""
    function getLength(str, target) {
        return str.split(target).length - 1
    }
    function dfs(index) {
        if (index === 2 * n) {
            res.push(path)
        } else {
            for (let item of ["(", ")"]) {
                if (item === "(" && getLength(path, "(") < n) {
                    path = path + "("
                    dfs(index + 1)
                    path = path.slice(0, path.length - 1)
                } else if (item === ")" && getLength(path, "(") > getLength(path, ")")) {
                    path = path + ")"
                    dfs(index + 1)
                    path = path.slice(0, path.length - 1)
                }
            }
        }
    }
    dfs(0)
    return res

13. 合并k个升序链表

 虽然是困难题,但是我的解决办法就是循环执行11题,两两排序。就比较简单了。

/**
 * 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 === 0) return null
    let res = lists[0]
    function sortTwoList(l1, l2) {
        let o = new ListNode()
        let res = o
        while (l1 && l2) {
            if (l1.val < l2.val) {
                o.next = l1
                l1 = l1.next
            } else {
                o.next = l2
                l2 = l2.next
            }
            o = o.next
        }
        while (l1) {
            o.next = l1
            o = o.next
            l1 = l1.next
        }
        while (l2) {
            o.next = l2
            o = o.next
            l2 = l2.next
        }
        return res.next
    }
    for (let i = 1; i < lists.length; i++) {
        res = sortTwoList(res, lists[i])
    }
    return res
};

14. 下一个排列

做的时候没啥思路太困了 看了官方的方法

/**
 * @param {number[]} nums
 * @return {void} Do not return anything, modify nums in-place instead.
 */
var nextPermutation = function(nums) {
    //逆序找变小值返回索引
    let indexMin = -1
    let changeIndex = -1
    for (let i = nums.length - 2; i >= 0; i--) {
        if (nums[i] < nums[i + 1]) {
            indexMin = i
            break
        }
    }
    if (indexMin === -1) return nums.sort((a, b) => a - b)
    //查找第一个比min大的数
    for (let i = nums.length; i >= indexMin; i--) {
        if (nums[i] > nums[indexMin]) {
            changeIndex = i
            break
        }
    }
    //交换两个数的位置
    let tempData = nums[indexMin]
    nums[indexMin] = nums[changeIndex]
    nums[changeIndex] = tempData
    //将后面的排序
    let tempArray = []
    for (let i = nums.length - 1; i > indexMin; i--) {
        tempArray.push(nums.pop())
    }
    nums.push(...tempArray)
};

15. 最长有效括号

开始懒得想直接暴力求解 果然超时

/**
 * @param {string} s
 * @return {number}
 */
var longestValidParentheses = function(s) {
    let maxLength = 0
    function judge(str) {
        let list = []
        for (let i = 0; i < str.length; i++) {
            let target = str.charAt(i)
            if (target === "(") {
                list.push("(")
            } else if (target === ")" && list[list.length - 1] === "(") {
                list.pop()
            } else {
                return false
            }
        }
        if (list.length === 0) return true
        return false
    }
    for (let pre = 0; pre < s.length; pre++) {
        for (let next = 1; next < s.length; next++) {
            if(s.length-pre<maxLength) return maxLength
            let target = s.slice(pre, next+1)
            if (judge(target)) {
                maxLength = maxLength > target.length ? maxLength : target.length
            }
        }
    }
    return maxLength
};

 后来直接去看答案 还是答案想的周到,这里采用双指针法

/**
 * @param {string} s
 * @return {number}
 */
var longestValidParentheses = function (s) {
    let left = 0
    let right = 0
    let maxLength = 0


    for (let i = 0; i < s.length; i++) {
        const target = s.charAt(i)
        if (target === "(") {
            left++
        } else if (target === ")") {
            right++
        }
        if (right > left) {
            right = 0
            left = 0
        }else if (left === right) {
            const length = 2 * right
            maxLength = maxLength > length ? maxLength : length
        }
    }
    right=left=0
    for (let i = s.length - 1; i >= 0; i--) {
        const target = s.charAt(i)
        if (target === "(") {
            left++
        } else if (target === ")") {
            right++
        }
        if (right < left) {
            right = 0
            left = 0
        }else if (left === right) {
            const length = 2 * left
            maxLength = maxLength > length ? maxLength : length
        }
    }

    return maxLength
};

关于贪心算法的补充

贪心算法详解

后面有几道过于简单的就省略掉了。

猜你喜欢

转载自blog.csdn.net/weixin_47964837/article/details/127593807