标签: LeetCode

  • “整数反转”问题的 Javascript 解答

    “整数反转”问题的 Javascript 解答

    题目

    给你一个 32 位的有符号整数 x ,返回将 x 中的数字部分反转后的结果。

    如果反转后整数超过 32 位的有符号整数的范围 [−231,  231 − 1] ,就返回 0。

    假设环境不允许存储 64 位整数(有符号或无符号)。
     

    示例 1:

    输入:x = 123
    输出:321


    示例 2:

    输入:x = -123
    输出:-321


    示例 3:

    输入:x = 120
    输出:21


    示例 4:

    输入:x = 0
    输出:0

    提示:

    -231 <= x <= 231 - 1

    分析

    将数当作字符串,反向遍历就能解决问题了,需要注意两个点:

    1. 负数的处理;
    2. 超出 32 位数范围,直接返回 0。

    解答

    /**
     * @param {number} x
     * @return {number}
     */
    var reverse = function (x) {
      var isNegativeNumber = false;
      if (x < 0) {
        isNegativeNumber = true;
      }
      var xStr = x.toString();
      var reverseXArr = [];
    
      for (var i = xStr.length - 1; i >= 0; i--) {
        reverseXArr.push(xStr[i]);
      }
    
      var result = parseInt(reverseXArr.join(""), 10);
    
      if (isNegativeNumber) {
        result = 0 - result;
      }
    
      if (result < -Math.pow(2, 31) || result > Math.pow(2, 31) - 1) {
        result = 0;
      }
    
      return result;
    };

    题目来源:力扣(LeetCode)

    链接:https://leetcode-cn.com/problems/reverse-integer

  • “Z 字形变换”问题的 Javascript 解答

    “Z 字形变换”问题的 Javascript 解答

    题目:

    将一个给定字符串 s 根据给定的行数 numRows ,以从上往下、从左到右进行 Z 字形排列。

    比如输入字符串为 “PAYPALISHIRING” 行数为 3 时,排列如下:

    P   A   H   N
    A P L S I I G
    Y   I   R
    之后,你的输出需要从左往右逐行读取,产生出一个新的字符串,比如:"PAHNAPLSIIGYIR"。
    请你实现这个将字符串进行指定行数变换的函数:
    
    string convert(string s, int numRows);

    示例 1:

    输入:s = "PAYPALISHIRING", numRows = 3
    输出:"PAHNAPLSIIGYIR"

    示例 2:

    输入:s = "PAYPALISHIRING", numRows = 4
    输出:"PINALSIGYAHRPI"
    解释:
    P     I    N
    A   L S  I G
    Y A   H R
    P     I

    示例3:

    输入:s = "A", numRows = 1
    输出:"A"

    思考:

    先找规律看看

    0123456
    0P[1]A[5]H[9]N[13]
    1A[2]P[4]L[6]S[8]I[10]I[12]G[14]
    2Y[3]I[7]R[11]
    示例1,numRows = 3
    0123456
    0P[0]I[6]N[12]
    1A[1]L[5]S[7]I[11]G[13]
    2Y[2]A[4]H[8]R[10]
    3P[3]I[9]
    示例2,numRows = 4

    设字符的下标为 n

    梯度(t) = numRows + (numRows -2),以示例2为例,梯度为 4 + (4 – 2) = 6

    计算列数(x) :

    nt = Math.floor(n / t) 得到字符 n 在第 nt 个梯度内(从 0 开始计数),每个梯度包含 tx 列,tx = numRows – 1

    n % t 将所有字符放在第一个梯度内考虑,有两种情况 :

    n % t < numRows 时,x 等于 0 + s[n] 所在的梯度乘以梯的长度,即: x = 0 + nt x tx,整理后是 x = nt x tx

    n % t >= numRows 时,也就是 s[n] 是在 “Z“ 字的折线位置的,放到第一个梯度里面看,x 应该就是 n % numRows 的值,属于其他梯度内的数,加上梯度即可,考虑到下标是从 0 开始的,所以 x = (((n % t) + 1) % numRows) + nt x tx;

    计算行数(y)

    行数的计算和列数的计算思路一样,把所有字符放到第一个梯度内考虑,而且不需要再加上梯度了。同样分两种情况:

    n % t < numRows 时,n % t 将 s[n] 放到第一个梯度内考虑,行数 y = n % numRows ,考虑梯度,最终结果为:y = n % t % numRows。

    n % t >= numRows 时,也就是计算 “Z” 字折线上的数字。n % t 将 s[n] 放到第一个梯度内考虑,观察 s[n] 的下标与行数的关系,可以得到 s[n] 不可能出现在第一行和最后一行,第一个梯度内,n + 1 – numRows 可得到 s[n] 到表格底部的距离,numRows – 1 再减去这个距离,就得到行数 y 了,因此结果为:y = numRows – 1 – ((n % t) + 1 – numRows)。

    还有一种情况是 numRows === 1 的时候,实际上把原字符串直接输出就是了。

    解答

    /**
     * @param {string} s
     * @param {number} numRows
     * @return {string}
     */
    var convert = function (s, numRows) {
      var matrix = [];
    
      for (var y = 0; y < numRows; y++) {
        // 构建行
        matrix[y] = [];
      }
    
      // 梯度
      var t = numRows + numRows - 2;
    
      for (var n = 0; n < s.length; n++) {
        // 测试列的判断逻辑是否正确
    
        // 初始化列位置
        var x = 0;
    
        // 初始化行位置
        var y = 0;
    
        // 得到元素在哪个梯度内
        var nt = Math.floor(n / t);
    
        // 每个梯度占据的列数
        var tx = numRows - 1;
    
        if (n % t < numRows) {
          x = 0 + nt * tx;
          y = (n % t) % numRows;
        } else {
          x = (((n % t) + 1) % numRows) + nt * tx;
          y = numRows - 1 - ((n % t) + 1 - numRows);
        }
    
        matrix[y][x] = s[n];
      }
    
      var result = "";
    
      matrix.forEach(function (element) {
        element.forEach(function (item) {
          if (item) result = result.padEnd(result.length + 1, item);
        });
      });
    
      return result;
    };
    

    题目来源:力扣(LeetCode)

    链接:https://leetcode-cn.com/problems/zigzag-conversion/

  • “最长回文子串”问题的 Javascript 解答

    “最长回文子串”问题的 Javascript 解答

    题目

    给你一个字符串 s,找到 s 中最长的回文子串。

    示例 1:

    输入:s = "babad"
    输出:"bab"
    解释:"aba" 同样是符合题意的答案。

    示例 2:

    输入:s = "cbbd"
    输出:"bb"

    示例 3:

    输入:s = "a"
    输出:"a"

    示例 4:

    输入:s = "ac"
    输出:"a"

    提示:

    1 <= s.length <= 1000
    s 仅由数字和英文字母(大写和/或小写)组成

    解题思路:

    先找相同字符形成的最长子串(A),如:‘aa’、‘aaa’、‘aaaa’;

    然后判断 A 的前面和后面距离与 A 距离相同的字符是否一样,如果一样,继续查找,直到不一样为止,就找到了一个回文字符串;

    遍历字符串,找到所有回文字符串,取出最长的一个。

    解答:

    var findPalindrome = function (s, i) {
      var j = 1;
    
      while (i + j < s.length && s[i] === s[i + j]) {
        j++;
      }
    
      var n = 0;
      while (
        i - n >= 0 &&
        i + (j - 1) + n < s.length &&
        s[i - n] === s[i + (j - 1) + n]
      ) {
        n = n + 1;
      }
    
      return s.substring(i - (n - 1), i + (j - 1) + n);
    };
    
    /**
     * @param {string} s
     * @return {string}
     */
    var longestPalindrome = function (s) {
      var result = "";
      for (var i = 0; i < s.length; i++) {
        var resulti = findPalindrome(s, i) || "";
    
        if (resulti.length > result.length) {
          result = resulti;
        }
      }
    
      return result;
    };
    

    题目来源:力扣(LeetCode)

    链接:https://leetcode-cn.com/problems/longest-palindromic-substring/

  • “寻找两个正序数组的中位数”问题的 Javascript 解答

    “寻找两个正序数组的中位数”问题的 Javascript 解答

    题目:

    给定两个大小分别为 m 和 n 的正序(从小到大)数组 nums1 和 nums2。请你找出并返回这两个正序数组的 中位数 。

    示例 1:

    输入:nums1 = [1,3], nums2 = [2]
    输出:2.00000
    解释:合并数组 = [1,2,3] ,中位数 2

    示例 2:

    输入:nums1 = [1,2], nums2 = [3,4]
    输出:2.50000
    解释:合并数组 = [1,2,3,4] ,中位数 (2 + 3) / 2 = 2.5

    示例 3:

    输入:nums1 = [0,0], nums2 = [0,0]
    输出:0.00000

    示例 4:

    输入:nums1 = [], nums2 = [1]
    输出:1.00000

    示例 5:

    输入:nums1 = [2], nums2 = []
    输出:2.00000

    提示:

    nums1.length == m
    nums2.length == n
    0 <= m <= 1000
    0 <= n <= 1000
    1 <= m + n <= 2000
    -106 <= nums1[i], nums2[i] <= 106

    进阶:你能设计一个时间复杂度为 O(log (m+n)) 的算法解决此问题吗?

    解题思路:

    将两个数组合并成一个数组后排序。

    如果合并后的数组的长度是偶数,取中间两个数的平均数;如果合并后的数组的长度是奇数,取中间的数。

    解答:

    var sortNumber = function (a, b) {
      return a - b;
    };
    
    /**
     * @param {number[]} nums1
     * @param {number[]} nums2
     * @return {number}
     */
    var findMedianSortedArrays = function (nums1, nums2) {
      var nums = nums1.concat(nums2).sort(sortNumber);
      var isEvenNum = nums.length % 2 === 0;
      var result = 0;
      var len = nums.length;
    
      if (isEvenNum) {
        result = (nums[len / 2 - 1] + nums[len / 2]) / 2;
      } else {
        result = nums[(len - 1) / 2];
      }
    
      return result;
    };

    题目来源:力扣(LeetCode)
    链接:https://leetcode-cn.com/problems/median-of-two-sorted-arrays

  • “无重复字符的最长子串(Longest Substring Without Repeating Characters)”问题的 Python3 解答

    “无重复字符的最长子串(Longest Substring Without Repeating Characters)”问题的 Python3 解答

    题目描述

    给定一个字符串,找出不含有重复字符的最长子串的长度。

    示例

    示例 1:

    输入: "abcabcbb"
    输出: 3 
    解释: 无重复字符的最长子串是 "abc",其长度为 3。
    

    示例2:

    输入: "bbbbb"
    输出: 1
    解释: 无重复字符的最长子串是 "b",其长度为 1。
    

    示例3:

    输入: "pwwkew"
    输出: 3
    解释: 无重复字符的最长子串是 "wke",其长度为 3。
         请注意,答案必须是一个子串,"pwke" 是一个子序列 而不是子串。
    

    测试用例

    abcabcbb    3
    bbbbb   1
    pwwkew  3
    ""      0
    au      2
    dvdf    3
    cdd     2
    ddc     2
    

    解题思路

    逐字符遍历字符串,记录第一个无重复子串s[0]。查看下一个字符是否被rStr所包含,不包含就将此字符加到rStr的末尾,直到找到一个已经包含在rStr中的字符,此时,这个无重复子串的长度就有了。依次方法,继续查找子串,并与当前已经找到的子串做比较,记录最长的子串长度即可。字符串遍历完毕,问题得解。

    解答

    class Solution:
        def lengthOfLongestSubstring(self, s):
            """
            :type s: str
            :rtype: int
            """
            sLen = len(s)
            if sLen < 1:
                return 0
            rLen = 1
            startIndex = 1
            endIndex = 0
            rStr = s[0]
    
            while startIndex != sLen != endIndex:
                for i in range(startIndex, sLen):
                    if s[i] not in rStr:
                        endIndex = i + 1
                        rStr = s[startIndex - 1:endIndex]
                    else:
                        break
                rLen = max(rLen, len(rStr))
                if startIndex != sLen:
                    rStr = s[startIndex]
                startIndex = startIndex + 1
            return rLen
    
    

    算法分析

    上述算法用Python3实现的时候有一个边界问题,字符串为空的情况下长度为 0,返回此值即可,否则下面初始化第一个无重复子串就溢出了。

    上述算法时间复杂度是O(n^2),并不理想。

    中文官网的题目地址:无重复字符的最长子串

  • “两数之和(Two Sum)”问题的 Python3 解答

    “两数之和(Two Sum)”问题的 Python3 解答

    题目描述

    给定一个整数数组和一个目标值,找出数组中和为目标值的两个数。你可以假设每个输入只对应一种答案,且同样的元素不能被重复利用。

    示例

    给定 nums = [2, 7, 11, 15], target = 9
    因为 nums[0] + nums[1] = 2 + 7 = 9
    所以返回 [0, 1]

    解题思路

    要求的结果是两个索引组成的 List:[aIndex, bIndex],这两个索引对应的值记为 a, b。

    遍历列表,假设列表中第1项的值 a 是结果 List 中的一个索引的值,那么用 target 减去 a 后得到的结果 b 就是就是要找的另一个索引的值,列表除掉 a 后的子列表里面,如果 b 存在,问题已解——答案是 a 的索引和 b 的索引组成的列表 [aIndex, bIndex]。

    如果不存在,将列表的第二项赋值给 a,继续寻找 b,直到找到为止。

    解答

    class Solution:
        def twoSum(self, nums, target):
            """
            :type nums: List[int]
            :type target: int
            :rtype: List[int]
            """
    
            i = 0
    
            for num in nums:
                nextNum = target - num
                j = i + 1
                if nextNum in nums[j:]:
                    return [i, nums[j:].index(nextNum) + i + 1]
                i += 1
    
    

    中文官网的题目地址:两数之和

  • “两数相加(Add Two Numbers)”问题的 Python3 解答

    “两数相加(Add Two Numbers)”问题的 Python3 解答

    题目描述

    给定两个非空链表来表示两个非负整数。位数按照逆序方式存储,它们的每个节点只存储单个数字。将两数相加返回一个新的链表。

    你可以假设除了数字 0 之外,这两个数字都不会以零开头

    示例

    输入:(2 -> 4 -> 3) + (5 -> 6 -> 4)
    输出:7 -> 0 -> 8
    原因:342 + 465 = 807

    测试用例

    [2,4,3]
    [5,6,4]
    
    [1]
    [9,9]
    
    [5]
    [5]
    
    [0]
    [7,3]
    
    [9,9]
    [9]
    

    解题思路

    遍历链表,按节点两两相加,有进位将进位加到下一个节点。

    解题思路很简单,此题被标记为中等难度,是因为:

    1. 数据结构是链表;
    2. 两个链表长度不一定相等,尤其是有进位情况下的处理需考虑。

    解答

    # Definition for singly-linked list.
    # class ListNode:
    #     def __init__(self, x):
    #         self.val = x
    #         self.next = None
    
    class Solution:
        def addTwoNumbers(self, l1, l2):
            """
            :type l1: ListNode
            :type l2: ListNode
            :rtype: ListNode
            """
            l3 = l1
    
            while l1 != None or l2 != None:
                sum = l1.val + l2.val
                l1.val = sum % 10
    
                if sum >= 10:
                    if l1.next != None:
                        l1.next.val = l1.next.val + 1
    
                        if l1.next.val >= 10 and l2.next == None:
                            l2.next = ListNode(0)
                    else:
                        l1.next = ListNode(1)
    
                else:
                    if l1.next == None and l2.next != None:
                        l1.next = ListNode(0)
    
                if l2.next == None:
                    break
    
                l1 = l1.next
                l2 = l2.next
    
            return l3
    

    算法分析

    上述算法通过一次遍历完成,没有用单独的变量存储 carry 值。两个链表同节点相加的结果最大为 9 + 9 + 1 = 19,所以结果链表中对应节点的值永远可以用(l1[index] + l2[index] + carry) % 10来得到。

    上述算法将进位 carry 计入到了下一位中。具体解题过程为

    1. 用新变量 l3 保留对 l1 的引用
    2. l1 和 l2 对应节点做加法
    3. 有进位且 l1 有下一节点的情况下,将进位加入到 l1 的下一个节点;l1 没有下一个节点就给 l1 添加一个值为 1 的节点;没有进位执行步骤4
    4. l1 没有下一个节点了,但是 l2 还有下一个节点,就给 l1 添加一个值为 0 的节点
    5. 3 或 4 步骤执行完毕,如果 l2 没值了,就跳出循环,返回 l3,原题得解;否则将 l1 和 l2 移动一个节点,执行步骤2

    中文官网的题目地址:两数相加