Leetcode热题100-part01

67 阅读2分钟

两数之和

  • 对于两个链表,从左向右遍历,遇到null补0,直到两个链表都是null,停止遍历;每一次将遍历的结果和上一次遍历的进位三者相加取余,所得结果作为新链表的节点值,所得进位参与下一次计算,若最后一次遍历得到进位,则新增一个节点存进位值。
/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
        ListNode newNode = new ListNode(0);
        ListNode pre = newNode;
        int cd = 0;

        while(l1 != null || l2 != null){
            int x = l1 != null ? l1.val : 0;
            int y = l2 != null ? l2.val : 0;

            int sum = x + y + cd;
            cd = sum / 10;
            sum = sum % 10;
            pre.next = new ListNode(sum);
            pre = pre.next;

            if(l1 != null){
                l1 = l1.next;
            }
            if(l2 != null){
                l2 = l2.next;
            }
        }
        if(cd >= 1){
            pre.next = new ListNode(cd);
        }
        return newNode.next;
    }
}

无重复字符的最长子串

  • 方法:滑动窗口。1、将字符串转成字符数组,创建一对快慢指针l和f。2、l指向窗口首位,f向后遍历,每新增一个元素,都要与前面所有元素比较是否相等,保证窗口内元素无重复。3、如果遇到重复元素,记录下此时的窗口元素个数并与之前的记录值作比较,取较大值,更新l指针指向该重复元素位置处的下一元素,f指针继续遍历。4、如果没有遇到重复元素则代表遍历已结束,同样将此时的窗口元素个数记录并比较,取较大值即为结果。
class Solution {
    public int lengthOfLongestSubstring(String s) {
        if(s.length() == 1){
            return 1;
        }
        char []ch = s.toCharArray();
        int lowIndex = 0;
        int fastIndex = 1;
        int res = 0;
        boolean sc = false;
        for(;fastIndex < s.length();fastIndex++){
            sc = false;
            for(int i = lowIndex; i < fastIndex; i++){
                if(ch[i] == ch[fastIndex] && i != fastIndex){
                    res = Math.max(fastIndex - lowIndex, res);
                    lowIndex = i + 1;
                    sc = true;
                    break;
                }
            }
            if(!sc){
                res = Math.max(fastIndex - lowIndex + 1, res);
            }
        }
        return res;
    }
}

寻找两个正序数组的中位数

  • 由于时间复杂度要求O(log(n + m)),显然本题要求使用二分法。思路:求中位数是一种特殊的求第n小的数的情况,当n+m为奇数时,即求解第(n + m)/2 + 1小的数(例如n+m=7,则求第4小的数),当n+m为偶数时,即求解第(n + m)/2小的数并与第(n + m)/2 + 1小的数求均值。
  • 现在开始讨论怎么求两个数组中第x小的数:想要求出第x小的数,由于两个数组按照从小到大顺序排列,则只需比较其下标为x/2的两个数的大小,然后将较小的那个数连同前面所有的数字删除,形成新的数组,此时问题变成了从新得到的两个数组中求第x/2小的数,从而得到了一个递归关系方程:f(num1[n],num2[m],x) = f(num1[n - x/2],num2[m],x/2) (n>=m),边界条件为n或m有一个变成0。这个过程相当于在合并数组并保留正序。
  • 如果较小的那个数组它的大小小于或等于x/2,那么我们直接比较它最大的数,即数组最右边的数。
class Solution {
public double findMedianSortedArrays(int[] nums1, int[] nums2) {
    int n = nums1.length;
    int m = nums2.length;
    int left = (n + m + 1) / 2;
    int right = (n + m + 2) / 2;
    //将偶数和奇数的情况合并,如果是奇数,会求两次同样的 k 。
    return (getKth(nums1, 0, n - 1, nums2, 0, m - 1, left) + getKth(nums1, 0, n - 1, nums2, 0, m - 1, right)) * 0.5;  
}
    
    private int getKth(int[] nums1, int start1, int end1, int[] nums2, int start2, int end2, int k) {
        int len1 = end1 - start1 + 1;
        int len2 = end2 - start2 + 1;
        //让 len1 的长度小于 len2,这样就能保证如果有数组空了,一定是 len1 
        if (len1 > len2) return getKth(nums2, start2, end2, nums1, start1, end1, k);
        if (len1 == 0) return nums2[start2 + k - 1];

        if (k == 1) return Math.min(nums1[start1], nums2[start2]);

        int i = start1 + Math.min(len1, k / 2) - 1;
        int j = start2 + Math.min(len2, k / 2) - 1;

        if (nums1[i] > nums2[j]) {
            return getKth(nums1, start1, end1, nums2, j + 1, end2, k - (j - start2 + 1));
        }
        else {
            return getKth(nums1, i + 1, end1, nums2, start2, end2, k - (i - start1 + 1));
        }
    }
}