[失业前端恶补算法]JavaScript leetcode刷题top100(五):两数相加、无重复字符的最长子串、最长回文子串、盛最多水的容器、三数之和

专栏声明:只求用最简单的,容易理解的方法通过,不求优化,不喜勿喷
今天更新五个中等难度题目:

两数相加

  • 题面
    给你两个非空的链表,表示两个非负的整数。它们每位数字都是按照逆序的方式存储的,并且每个节点只能存储 一位 数字。
    请你将两个数相加,并以相同形式返回一个表示和的链表。
    你可以假设除了数字 0 之外,这两个数都不会以 0 开头。

  • 知识点:
    链表,模拟

  • 思路
    模拟加法的操作,因为是逆序的数字链表,所以我们从两个链表头开始遍历链表即可,每次将两个数字相加并且加上进位标记(上一次结果有没有进位),放到新链表中,然后相加的结果超过10,我们对10取余,然后将进位存储在一个进位标记中,如果出现一个链表到底的情况,那么本次相加时,它是 0
    遍历两个链表,直到两个链表都遍历到底部,并且进位为0即可

  • 代码

var addTwoNumbers = function(l1, l2) {
    let head = null, tail = null;
    let carry = 0;
    while (l1 || l2) {
        const n1 = l1 ? l1.val : 0;
        const n2 = l2 ? l2.val : 0;
        const sum = n1 + n2 + carry;
        if (!head) {
            head = tail = new ListNode(sum % 10);
        } else {
            tail.next = new ListNode(sum % 10);
            tail = tail.next;
        }
        carry = Math.floor(sum / 10);
        if (l1) {
            l1 = l1.next;
        }
        if (l2) {
            l2 = l2.next;
        }
    }
    if (carry > 0) {
        tail.next = new ListNode(carry);
    }
    return head;
};

无重复字符的最长子串

  • 题面
    给定一个字符串 s ,请你找出其中不含有重复字符的 最长子串 的长度。
  • 知识点
    字符串、哈希表、滑动窗口
  • 思路
    初始化一个哈希表来存储我们的字符,遍历我们是字符串,然后用另一个变量记录当前字符串的开头位置
    每次遇到一个字符,如果是没出现过的,那么我们直接把它记录到哈希表里,然后更新长度
    如果出现过,那么我们更新字符串的开头位置,开头位置一直向前,期间从哈希表里删除经过的字母,直到删除现在正在遍历的字母位置,然后把现在遍历的字母记录到哈希表里,最后更新长度
  • 代码
var lengthOfLongestSubstring = function (s) {
    let hash = new Array(200).fill(0);
    let a = 0;
    let max = 0;
    for (var i = 0; i < s.length; i++) {
        let t = s.charCodeAt(i);
        if(hash[t] != 0 ){
            while(s[a]!=s[i]){
                hash[s.charCodeAt(a)] = 0;
                a++;
            }
            hash[s.charCodeAt(a)] = 0;
            a++;
        }
        max = Math.max(i - a + 1,max);
        hash[t] = 1;
    }
    return max;
};

最长回文子串

  • 题面
    给你一个字符串 s,找到 s 中最长的回文子串。
    如果字符串的反序与原始字符串相同,则该字符串称为回文字符串。
  • 知识点
    回文串,动态规划
  • 思路
    我们使用一个二位数组来记录 [ i , j ] 之间是不是回文串,我们遍历每一位,它有三种情况:
    当遍历 i 和它本身时,肯定是一个回文串,记录为 true
    当遍历 i 和 i + 1 时,只有这两个数相等,他们才是回文串,否则不是
    当遍历 i 和 i + 2 以及以上的时候,需要他们相等,并且 i + 1 和 j - 1 也是回文串,它才是回文串
    对于每一组 i 和 j ,如果它是回文串并且比现在记录的长,更新返回的回文串
  • 代码
var longestPalindrome = function (s) {
    var n = s.length;
    var d = [];
    for (var k = 0; k < n; k++) {
        d.push([]);
    }
    var ans = '';
    var j;
    for (var l = 1; l <= n; l++) {
        for (var i = 0; i < n; i++) {
            j = i + l - 1;
            if (j >= n) break;
            if (i == j) d[i][j] = true;
            else if (j == i + 1) d[i][j] = (s[i] == s[j])
            else {
                d[i][j] = d[i + 1][j - 1] && (s[i] == s[j])
            }
            if (d[i][j]) {
                ans = s.slice(i, j + 1);
            }
        }
    }
    return ans;
};

盛最多水的容器

  • 题面
    给定一个长度为 n 的整数数组 height 。有 n 条垂线,第 i 条线的两个端点是 (i, 0) 和 (i, height[i]) 。
    找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。
    返回容器可以储存的最大水量。
    说明:你不能倾斜容器。
  • 知识点
    双指针,贪心
  • 思路
    我们用两个指针来更新我们的容器,一个指向下标 0 ,一个指向数组最后一位 ,每次我们更新两个指针中较为矮的一个,然后计算他们的盛水量,直到两个指针相遇
  • 代码
var maxArea = function (height) {
    let b = height.length;
    let max = 0;
    let i = 0;
    let j = b;
    while (i < j) {
        let area = Math.min(height[i], height[j]) * (j - i);
        if (area > max) {
            max = area
        }
        if (height[j] > height[i]) {
            i++;
        }
        else {
            j--;
        }
    }
    return max;
};

三数之和

  • 题面
    给你一个整数数组 nums ,判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i != j、i != k 且 j != k ,同时还满足 nums[i] + nums[j] + nums[k] == 0 。请你返回所有和为 0 且不重复的三元组。
    注意:答案中不可以包含重复的三元组。
  • 知识点
    双指针
  • 思路
    首先对我们的数组排序,只有有序的数组可以使用双指针,之后遍历每一位,对于每一位 i ,我们用两个指针寻找需要的剩下两个数,他们的和要等于 0 - nums [ i ] ,要注意的一点是不能重复,所以我们每次只计算相同的元素中,最靠近另一个指针的那一项即可
  • 代码
var threeSum = function (nums) {
    var ret = [];
    nums.sort(function (a, b) {
        return a - b;
    })
    for (var i = 0; i < nums.length - 1; i++) {
        var a = i + 1;
        var b = nums.length - 1;
        if (i != 0 && nums[i] == nums[i - 1]) {
            continue;
        }
        var re = 0 - nums[i];
        while (a < b) {
            if (nums[a] + nums[b] < re) {
                a++;
                while (nums[a - 1] == nums[a]) {
                    a++;
                }
            } else if (nums[a] + nums[b] > re) {
                b--;
                while (nums[b + 1] == nums[b]) {
                    b--;
                }
            } else {
                ret.push([nums[a], nums[i], nums[b]]);
                a++;
                while (nums[a - 1] == nums[a]) {
                    a++;
                }
                b--;
                while (nums[b + 1] == nums[b]) {
                    b--;
                }
            }
        }
    }
    return ret;
};

你可能感兴趣的:(失业前端恶补算法,前端,算法,javascript,双指针)