代码

12 阅读2分钟

无重复字符的最长子串

题解:

哈希+双指针,哈希保存char的坐标,如果出现重复字符就移动窗口

var lengthOfLongestSubstring = function(s) {    if(s.length===0) return 0;    let left=0;    let maxLength = 0;    const map = new Map();        for(let right=0; right<s.length; right++){        const char = s[right];        if(map.has(char)){            left = Math.max(left,map.get(char)+1)//保证窗口一直向右滑动        }        map.set(char,right)        maxLength = Math.max(maxLength,right-left+1)    }    return maxLength;};

LRU缓存

题解:双向链表

反转链表

题解:

保留三个指针:prev,current,next,前两个交换指向,后一个保留链表的引用

数组中第k大

题解:快排

var findKthLargest = function (nums, k) {    const targetIndex = nums.length - k;    return quickSelect(0, nums.length - 1, targetIndex, nums);};const quickSelect = (left, right, k, arr) => {    if (left === right) return arr[left];    const pivotIndex = partition(left, right, arr);    if (k === pivotIndex) {        return arr[pivotIndex];    } else if (k < pivotIndex) {        return quickSelect(left, pivotIndex - 1, k, arr);    } else {        return quickSelect(pivotIndex + 1, right, k, arr);    }};const partition = (left, right, arr) => {    const pivot = arr[left];    let l = left + 1;    let r = right;    while (l <= r) {        while (l <= r && arr[l] <= pivot) { l++; } while (l <= r && arr[r] > pivot) { r--; }        if (l < r) {            //重要,确保不要打乱已分区的部分                        [arr[l], arr[r]] = [arr[r], arr[l]];        }    }    // 将基准值放到正确位置        [arr[left], arr[r]] = [arr[r], arr[left]];    return r;};

快排

注意点:

  • if(left >= right) return;

  • while(l<=r)

    var sortArray = function(nums) { quickSort(0,nums.length-1,nums) return nums;};function quickSort(left,right,arr){ // 空数组时会出现left>right if(left >= right) return; const pivotIndex = partition(left,right,arr); quickSort(left,pivotIndex-1,arr); quickSort(pivotIndex+1,right,arr);}function partition(left,right,arr){ const pivot = arr[left] let l = left+1; let r = right; while(l<=r){ while(l<=r && arr[l]<=pivot){ l++; } while(l<=r && arr[r]>pivot){ r--; } if(l<r){ [arr[l],arr[r]]=[arr[r],arr[l]] } } [arr[left],arr[r]]=[arr[r],arr[left]] return r;}

K个一组反转链表

题解:

第一个节点:空节点dummy ---> 初始prev

第二个节点:head ---> 初始cur

1、写一个反转函数,返回newHead,newTail,nextGroup

2、反转前判断是否足k个

3、反转后连接链表,移动指针:上一组和这一组连接,这一组和下一组连接,更新pre和cur指针

var reverseKGroup = function(head, k) {    // 辅助函数:反转链表的前 k 个节点    function reverse(prev, head, k) {        let current = head;        while (k > 0 && current) {            const next = current.next;            current.next = prev;            prev = current;            current = next;            k--;        }        return { newTail: head, newHead: prev, nextGroup: current };    }    // 处理空链表    if (!head) return null;    const dummy = new ListNode(0);    dummy.next = head;    let prevGroupTail = dummy; // 上一组的尾节点    let current = head;    while (true) {        // 检查剩余节点是否足够 k 个        let temp = current;        let count = k;        while (count > 0 && temp) {            temp = temp.next;            count--;        }        if (count > 0) break; // 不足 k 个,直接退出        // 反转当前 k 个节点        const { newTail, newHead, nextGroup } = reverse(prevGroupTail, current, k);                // 连接反转后的组        prevGroupTail.next = newHead;//连接上一组和这一组        newTail.next = nextGroup;//连接这一组和下一组        prevGroupTail = newTail; // 更新prev为这一组的尾节点        current = nextGroup;     // 移动到下一组    }    return dummy.next;};

三数之和

题解:排序➕双指针

排序之后方便跳过重复的数字,以及根据结果大小决定左右指针移动的方向

var threeSum = function (nums) {    const res = [];    const len = nums.length;    nums.sort((a, b) => a - b)    for (let i = 0; i < len; i++) {        if (nums[i] > 0) break;        if (i > 0 && nums[i] === nums[i - 1]) continue;        let left = i + 1;        let right = len - 1;        while (left < right) {            const sum = nums[i] + nums[left] + nums[right];            if (sum === 0) {                res.push([nums[i], nums[left], nums[right]]);                //跳过后续重复的数字                while (left < right && nums[left] === nums[left + 1]) {                    left++;                }                while (left < right && nums[right] === nums[right - 1]) {                    right--;                }                //正常移动                left++;                right--;            } else if (sum < 0) {                left++;            } else {                right--;            }        }    }    return res;};

最大子数组和

题解:动态规划

以该元素结尾时的最大和(要么加上前面的部分,要么从这个数字重新开始)

var maxSubArray = function(nums) {    let curSum = nums[0];    let maxSum = nums[0];    for(let i=1; i<nums.length; i++){        // 以该元素结尾的最大和(要么加上前面的部分,要么从这个数字重新开始)        curSum = Math.max(nums[i],curSum+nums[i]);        // 全局最大和        maxSum = Math.max(maxSum,curSum)    }    return maxSum;};

最长回文子串

方法一:动态规划

题解:比较s[i]、s[j],若相等则取决于dp[i+1][j-1]是否为回文

var longestPalindrome = function(s) {    const n = s.length;    if(n<2) return s;    let maxLen = 1;    let begin = 0;    const dp = Array.from({length:n},()=>Array.from({length:n},() => false))    for(let i=0; i<n; i++){        dp[i][i]=true;    }    for(let j=1; j<n; j++){        for(let i=0; i<j; i++){            if(s[i] != s[j]){                dp[i][j] = false;            }else{                if(j-i<3){                    dp[i][j]=true;                }else{                    dp[i][j] = dp[i+1][j-1];                }                if(dp[i][j] && j-i+1>maxLen){                    maxLen = j-i+1;                    begin = i;                }            }        }    }    return s.substring(begin,begin+maxLen)};

方法二:中心扩散法(更优解)

题解:

从中心向外同步扩散,如果相等就继续扩散

注意奇数是从i扩散,偶数从i和i+1扩散

var longestPalindrome = function(s) {    const len = s.length;    if(len<2) return s;    let res='';    for(let i=0; i<len; i++){        helper(i,i)        helper(i,i+1)    }    function helper(m,n){        while(m>=0 && n < len && s[m]===s[n]){            m--;            n++;        }        if(n-m-1 > res.length){            res = s.slice(m+1,n)        }    }    return res;};