《剑指offer》专项突破

news2024/11/18 3:38:47

第一章:整数

面试题1:整数除法

题目

输入两个int型整数,求它们除法的商,要求不得使用乘号’*‘、除号’/‘以及求余符号’%'。当发生溢出时返回最大的整数值。假设除数不为0。例如,输入152,输出15/2的结果,即7

参考代码

public int divide(int dividend, int divisor) {
   
    if (dividend == 0x80000000 && divisor == -1){
   
        return Integer.MAX_VALUE;
    }

    int negative = 2;
    if (dividend > 0) {
   
        negative--;
        dividend = -dividend;
    }

    if (divisor > 0) {
   
        negative--;
        divisor = -divisor;
    }

    int result = divideCore(dividend, divisor);
    return negative == 1 ? -result : result;
}

private int divideCore(int dividend, int divisor) {
   
    int result = 0;
    while (dividend <= divisor) {
   
        int value = divisor;
        int quotient = 1;
        while (value >= 0xc0000000 && dividend <= value + value) {
   
            quotient += quotient;
            value += value;
        }

        result += quotient;
        dividend -= value;
    }

    return result;
}

面试题2:二进制加法

题目

输入两个表示二进制的字符串,请计算它们的和,并以二进制字符串的形式输出。例如输入的二进制字符串分别是"11"和"10",则输出"101"。

参考代码

public String addBinary(String a, String b) {
   
    StringBuilder result = new StringBuilder();
    int i = a.length() - 1;
    int j = b.length() - 1;
    int carry = 0;
    while (i >= 0 || j >= 0) {
   
        int digitA = i >= 0 ? a.charAt(i--) - '0' : 0;
        int digitB = j >= 0 ? b.charAt(j--) - '0' : 0;
        int sum = digitA + digitB + carry;
        carry = sum >= 2 ? 1 : 0;
        sum = sum >= 2 ? sum - 2 : sum;
        result.append(sum);
    }

    if (carry == 1) {
   
        result.append(1);
    }

    return result.reverse().toString();
}

面试题3:前n个数字二进制中1的个数

题目

输入一个非负数n,请计算0n之间每个数字的二进制表示中1的个数,并输出一个数组。例如,输入n4,由于0、1、2、3、4的二进制表示的1的个数分别为0、1、1、2、1,因此输出数组[0, 1, 1, 2, 1]

参考代码

解法一
public int[] countBits(int num) {
   
    int[] result = new int[num + 1];
    for (int i = 0; i <= num; ++i) {
   
        int count = 0;
        int j = i;
        while (j != 0) {
   
            result[i]++;
            j = j & (j - 1);
        }
    }

    return result;
}
解法二
public int[] countBits(int num) {
   
    int[] result = new int[num + 1];
    for (int i = 1; i <= num; ++i) {
   
        result[i] = result[i & (i - 1)] + 1;
    }

    return result;
}
解法三
public int[] countBits(int num) {
   
    int[] result = new int[num + 1];
    for (int i = 1; i <= num; ++i) {
   
        result[i] = result[i >> 1] + (i & 1);
    }

    return result;
}

面试题4:只出现一次的数字

题目

输入一个整数数组,数组中除一个数字只出现一次之外其他数字都出现三次。请找出那个唯一只出现一次的数字。例如,如果输入的数组为[0, 1, 0, 1, 0, 1, 100],则只出现一次的数字时100

参考代码

public int singleNumber(int[] nums) {
   
    int[] bitSums = new int[32];
    for (int num : nums) {
   
        for (int i = 0; i < 32; i++) {
   
            bitSums[i] += (num >> (31 - i)) & 1;
        }
    }

    int result = 0;
    for (int i = 0; i < 32; i++) {
   
        result = (result << 1) + bitSums[i] % 3;
    }

    return result;
}

面试题5:单词长度的最大乘积

题目

输入一个字符串数组words,请计算当两个字符串words[i]words[j]不包含相同字符时它们长度的乘积的最大值。如果没有不包含相同字符的一对字符串,那么返回0。假设字符串中只包含英语的小写字母。例如,输入的字符串数组words["abcw", "foo", "bar", "fxyz","abcdef"],数组中的字符串"bar"与"foo"没有相同的字符,它们长度的乘积为9。“abcw"与” fxyz "也没有相同的字符,它们长度的乘积是16,这是不含相同字符的一对字符串的长度乘积的最大值。

参考代码

public int maxProduct(String[] words) {
   
    boolean[][] flags = new boolean[words.length][26];
    for (int i = 0; i < words.length; i++) {
   
        for(char c: words[i].toCharArray()) {
   
            flags[i][c - 'a'] = true;
        }
    }

    int result = 0;
    for (int i = 0; i < words.length; i++) {
   
        for (int j = i + 1; j < words.length; j++) {
   
            int k = 0;
            for (; k < 26; k++) {
   
                if (flags[i][k] && flags[j][k]) {
   
                    break;
                }
            }

            if (k == 26) {
   
                int prod = words[i].length() * words[j].length();
                result = Math.max(result, prod);
            }
        }
    }

    return result;
}

第二章:数组

面试题6:排序数组中两个数字之和

题目

输入一个递增排序的数组和一个值k,请问如何在数组中找出两个和为k的数字并返回它们的下标?假设数组中存在且只存在一对符合条件的数字,同时一个数字不能使用两次。例如输入数组[1, 2, 4, 6, 10]k的值为8,数组中的数字26的和为8,它们的下标分别为13

参考代码

public int[] twoSum(int[] numbers, int target) {
   
    int i = 0;
    int j = numbers.length - 1;
    while (i < j && numbers[i] + numbers[j] != target) {
   
        if (numbers[i] + numbers[j] < target) {
   
            i++;
        } else {
   
            j--;
        }
    }

    return new int[] {
   i, j};
}

面试题7:数组中和为0的三个数字

题目

输入一个数组,如何找出数组中所有和为0的三个数字的三元组?注意返回值中不得包含重复的三元组。例如在数组中[-1, 0, 1, 2, -1, -4]中有两个三元组的和为0,它们分别是[-1, 0, 1][-1, -1, 2]

参考代码

public List<List<Integer>> threeSum(int[] nums) {
   
    List<List<Integer>> result = new LinkedList<List<Integer>>();
    if (nums.length >= 3) {
   
        Arrays.sort(nums);

        int i = 0;
        while(i < nums.length - 2) {
   
            twoSum(nums, i, result);

            int temp = nums[i];
            while(i < nums.length && nums[i] == temp) {
   
                ++i;
            }
        }
    }

    return result;
}

private void twoSum(int[] nums, int i, List<List<Integer>> result) {
   
    int j = i + 1;
    int k = nums.length - 1;
    while (j < k) {
   
        if (nums[i] + nums[j] + nums[k] == 0) {
   
            result.add(Arrays.asList(nums[i], nums[j], nums[k]));

            int temp = nums[j];
            while (nums[j] == temp && j < k) {
   
                ++j;
            }
        } else if (nums[i] + nums[j] + nums[k] < 0) {
   
            ++j;
        } else {
   
            --k;
        }
    }
}

面试题8:和大于等于k的最短子数组

题目

输入一个正整数组成的数组和一个正整数k,请问数组中和大于或等于k的连续子数组的最短长度是多少?如果不存在所有数字之和大于k的子数组,则返回0。例如输入数组[5, 1, 4, 3]k的值为7,和大于或等于7的最短连续子数组是[4, 3],因此输出它的长度2

参考代码

public int minSubArrayLen(int k, int[] nums) {
   
    int left = 0;
    int sum = 0;
    int minLength = Integer.MAX_VALUE;
    for (int right = 0; right < nums.length; right++) {
   
        sum += nums[right];
        while (left <= right && sum >= k) {
   
            minLength = Math.min(minLength, right - left + 1);
            sum -= nums[left++];
        }
    }

    return minLength == Integer.MAX_VALUE ? 0 : minLength;
}

面试题9:乘积小于k的子数组

题目

输入一个由正整数组成的数组和一个正整数k,请问数组中有多少个数字乘积小于k的连续子数组?例如输入数组[10, 5, 2, 6]k的值为100,有8个子数组的所有数字的乘积小于100,它们分别是[10]、[5]、[2]、[6]、[10, 5]、[5, 2]、[2, 6]和[5, 2, 6]

参考代码

public int numSubarrayProductLessThanK(int[] nums, int k) {
   
    long product = 1;
    int left = 0;
    int count = 0;
    for (int right = 0; right < nums.length; ++right) {
   
        product *= nums[right];
        while (left <= right && product >= k) {
   
            product /= nums[left];
            left++;
        }

        count += right >= left ? right - left + 1 : 0;
    }

    return count;
}

面试题10:和为k的子数组

题目:输入一个整数数组和一个整数k,请问数组中有多少个数字之和等于k的连续子数组?例如输入数组[1, 1, 1]k的值为2,有2个连续子数组之和等于2

参考代码

public int subarraySum(int[] nums, int k) {
   
    Map<Integer, Integer> sumToCount = new HashMap<>();
    sumToCount.put(0, 1);
    int sum = 0;
    int count = 0;
    for (int num : nums) {
   
        sum += num;
        count += sumToCount.getOrDefault(sum - k, 0);
        sumToCount.put(sum, sumToCount.getOrDefault(sum, 0) + 1);
    }

    return count;
}

面试题11:0和1个数相同的子数组

题目

输入一个只包含01的数组,请问如何求最长01的个数相同的连续子数组的长度?例如在数组[0, 1, 0]中有两个子数组包含相同个数的01,分别是[0, 1][1, 0],它们的长度都是2,因此输出2

参考代码

public int findMaxLength(int[] nums) {
   
    Map<Integer, Integer> sumToIndex = new HashMap();
    sumToIndex.put(0, -1);
    int sum = 0;
    int maxLength = 0;
    for (int i = 0; i < nums.length; ++i) {
   
        sum += nums[i] == 0 ? -1 : 1;
        if (sumToIndex.containsKey(sum)) {
   
            maxLength = Math.max(maxLength, i - sumToIndex.get(sum));
        } else {
   
            sumToIndex.put(sum, i);
        }
    }

    return maxLength;
}

面试题12:左右两边子数组的和相等

题目

输入一个整数数组,如果一个数字左边的子数组数字之和等于右边的子数组数字之和,请返回该数字的下标。如果存在多个这样的数字,则返回最左边一个的下标。如果不存在这样的数字,则返回-1。例如在数组1, 7, 3, 6, 2, 9]中,下标为3的数字(值为6)左边三个数字1、7、3和右边两个数字29的和相等,都是11,因此正确的输出值是3

参考代码

public int pivotIndex(int[] nums) {
   
    int total = 0;
    for (int num : nums) {
   
        total += num;
    }

    int sum = 0;
    for (int i = 0; i < nums.length; ++i) {
   
        sum += nums[i];
        if (sum - nums[i] == total - sum) {
   
            return i;
        }
    }

    return -1;
}

面试题13:二维子矩阵的和

题目

输入一个二维矩阵,如何计算给定左上角坐标和右下角坐标的子矩阵数字之和?对同一个二维矩阵,计算子矩阵数字之和的函数可能输入不同的坐标而被反复调用多次。例如输入图2.1中的二维矩阵,以及左上角坐标为(2, 1)和右下角坐标为(4, 3),该函数输出8

2.1
图2.1:在一个5×5的二维数组中左上角坐标为(2, 1)、右下角坐标为(4, 3)的子矩阵(有灰色背景部分)的和等于8

参考代码

class NumMatrix {
   
    private int[][] sums;
 
    public NumMatrix(int[][] matrix) {
   
        if (matrix.length == 0 || matrix[0].length == 0) {
   
            return;
        }
        
        sums = new int[matrix.length + 1][matrix[0].length + 1];
        for (int i = 0; i < matrix.length; ++i) {
   
            int rowSum = 0;
            for (int j = 0; j < matrix[0].length; ++j) {
   
                rowSum += matrix[i][j];
                sums[i + 1][j + 1] = sums[i][j + 1] + rowSum;
            }
        }
    }
    
    public int sumRegion(int row1, int col1, int row2, int col2) {
   
        return sums[row2 + 1][col2 + 1] - sums[row1][col2 + 1]
            - sums[row2 + 1][col1] + sums[row1][col1]; 
    }
}

第三章:字符串

面试题14:字符串中的变位词

题目

输入两个字符串s1s2,如何判断s2中是否包含s1的某个变位词?如果s2中包含s1的某个变位词,则s1至少有一个变位词是s2的子字符串。假设两个输入字符串中只包含英语小写字母。例如输入字符串s1为"ab",s2为"dgcaf",由于s2中包含s1的变位词"ba",因此输出是true。如果输入字符串s1为"ac",s2为"dcgaf",输出为false

参考代码

public boolean checkInclusion(String s1, String s2) {
   
    if (s2.length() >= s1.length()) {
   
        int[] counts = new int[26];
        for (int i = 0; i < s1.length(); ++i) {
   
            counts[s1.charAt(i) - 'a']++;
            counts[s2.charAt(i) - 'a']--;
        }

        if (areAllZero(counts)) {
   
            return true;
        }

        for (int i = s1.length(); i < s2.length(); ++i) {
   
            counts[s2.charAt(i) - 'a']--;
            counts[s2.charAt(i - s1.length()) - 'a']++;
            if (areAllZero(counts)) {
   
                return true;
            }
        }
    }

    return false;
}

private boolean areAllZero(int[] counts) {
   
    for (int count : counts) {
   
        if (count != 0) {
   
            return false;
        }
    }

    return true;
}

面试题15:字符串中的所有变位词

题目

输入两个字符串s1s2,如何找出s2的所有变位词在s1中的起始下标?假设两个输入字符串中只包含英语小写字母。例如输入字符串s1为"cbadabacg",s2为"abc",s2有两个变位词"cba"和"bac"是s1中的字符串,输出它们在s1中的起始下标05

参考代码

    public List<Integer> findAnagrams(String s1, String s2) {
   
        List<Integer> indices = new LinkedList<>();
        if (s1.length() >= s2.length()) {
   
            int[] counts = new int[26];
            for (int i = 0; i < s2.length(); ++i) {
   
                counts[s2.charAt(i) - 'a']++;
                counts[s1.charAt(i) - 'a']--;
            }

            if (areAllZero(counts)) {
   
                indices.add(0);
            }

            for (int i = s2.length(); i < s1.length(); ++i) {
   
                counts[s1.charAt(i) - 'a']--;
                counts[s1.charAt(i - s2.length()) - 'a']++;
                if (areAllZero(counts)) {
   
                    indices.add(i - s2.length() + 1);
                }
            }
        }
        
        return indices;
    }
    
    private boolean areAllZero(int[] counts) {
   
        for (int count : counts) {
   
            if (count != 0) {
   
                return false;
            }
        }
        
        return true;
    }

面试题16:不含重复字符的最长子字符串

题目

输入一个字符串,求该字符串中不含重复字符的最长连续子字符串的长度。例如,输入字符串"babcca",它最长的不含重复字符串的子字符串是"abc",长度为3

参考代码

解法一
public int lengthOfLongestSubstring(String s) {
   
    int[] counts = new int[256];
    int longest = s.length() > 0 ? 1 : 0;
    for (int i = 0, j = -1; i < s.length(); ++i) {
   
        counts[s.charAt(i)]++;
        while (hasGreaterThan1(counts)) {
   
            ++j;
            counts[s.charAt(j)]--;
        }

        longest = Math.max(i - j, longest);
    }

    return longest;
}

private boolean hasGreaterThan1(int[] counts) {
   
    for (int count : counts) {
   
        if (count > 1) {
   
            return true;
        }
    }

    return false;
}    
解法二
public int lengthOfLongestSubstring(String s) {
   
    int[] counts = new int[256];
    int longest = s.length() > 0 ? 1 : 0;
    int countDup = 0;
    for (int i = 0, j = -1; i < s.length(); ++i) {
   
        counts[s.charAt(i)]++;
        if (counts[s.charAt(i)] == 2) {
   
            countDup++;
        }

        while (countDup > 0) {
   
            ++j;
            counts[s.charAt(j)]--;
            if (counts[s.charAt(j)] == 1) {
   
                countDup--;
            }
        }

        longest = Math.max(i - j, longest);
    }

    return longest;
}

面试题17:含有所有字符的最短字符串

题目

输入两个字符串st,请找出s中包含t的所有字符的最短子字符串。例如输入s为字符串"ADDBANCAD",t为字符串"ABC",则s中包含字符’A’、‘B’、'C’的最短子字符串是"BANC"。如果不存在符合条件的子字符串,返回空字符串""。如果存在多个符合条件的子字符串,返回任意一个

参考代码

public String minWindow(String s, String t) {
   
    HashMap<Character, Integer> charToCount = new HashMap<>();
    for (char ch : t.toCharArray()) {
   
        charToCount.put(ch, charToCount.getOrDefault(ch, 0) + 1);
    }

    int count = charToCount.size();
    int start = 0, end = 0, minStart = 0, minEnd = 0;
    int minLength = Integer.MAX_VALUE;
    while (end < s.length() || (count == 0 && end == s.length())) {
   
        if (count > 0) {
   
            char endCh = s.charAt(end);
            if (charToCount.containsKey(endCh)) {
   
                charToCount.put(endCh, charToCount.get(endCh) - 1);
                if (charToCount.get(endCh) == 0) {
   
                    count--;
                }
            }

            end++;
        } else {
   
            if (end - start < minLength) {
   
                minLength = end - start;
                minStart = start;
                minEnd = end;
            }

            char startCh = s.charAt(start);
            if (charToCount.containsKey(startCh)) {
   
                charToCount.put(startCh, charToCount.get(startCh) + 1);
                if (charToCount.get(startCh) == 1) {
   
                    count++;
                }
            }

            start++;
        }
    }

    return minLength < Integer.MAX_VALUE
        ? s.substring(minStart, minEnd)
        : "";
}

面试题18:有效的回文

题目

给定一个字符串,请判断它是不是一个回文字符串。我们只需要考虑字母或者数字字符,并忽略大小写。例如,"A man, a plan, a canal: Panama"是一个回文字符串,而"race a car"不是。

参考代码

public boolean isPalindrome(String s) {
   
    int i = 0;
    int j = s.length() - 1;
    while (i < j) {
   
        char ch1 = s.charAt(i);
        char ch2 = s.charAt(j);
        if (!Character.isLetterOrDigit(ch1)) {
   
            i++;
        } else if (!Character.isLetterOrDigit(ch2)) {
   
            j--;
        } else {
   
            ch1 = Character.toLowerCase(ch1);
            ch2 = Character.toLowerCase(ch2);
            if (ch1 != ch2) {
   
                return false;
            }

            i++;
            j--;
        }       
    }

    return true;
}

面试题19:最多删除一个字符得到回文

题目

给定一个字符串,请判断如果最多从字符串中删除一个字符能不能得到一个回文字符串。例如,如果输入字符串"abca",由于删除字符’b’或者’c’就能得到一个回文字符串,因此输出为true

参考代码

public boolean validPalindrome(String s) {
   
    int start = 0;
    int end = s.length() - 1;
    for (; start < s.length() / 2; ++start, --end) {
   
        if (s.charAt(start) != s.charAt(end)) {
   
            break;
        }
    }

    return start == s.length() / 2
        || isPalindrome(s, start, end - 1)
        || isPalindrome(s, start + 1, end);
}

private boolean isPalindrome(String s, int start, int end) {
   
    while (start < end) {
   
        if (s.charAt(start) != s.charAt(end)) {
   
            break;
        }

        start++;
        end--;
    }

    return start >= end;
}

面试题20:回文子字符串的个数

题目

给定一个字符串,请问字符串里有多少回文连续子字符串?例如,字符串里"abc"有3个回文字符串,分别为"a"、“b”、“c”;而字符串"aaa"里有6个回文子字符串,分别为"a"、“a”、“a”、“aa”、“aa"和"aaa”。

参考代码

    public int countSubstrings(String s) {
   
        if (s == null || s.length() == 0) {
   
            return 0;
        }
        
        int count = 0;
        for (int i = 0; i < s.length(); ++i) {
   
            count += countPalindrome(s, i, i);
            count += countPalindrome(s, i, i + 1);
        }
        
        return count;
    }
    
    private int countPalindrome(String s, int start, int end) {
   
        int count = 0;
        while (start >= 0 && end < s.length()
               && s.charAt(start) == s.charAt(end)) {
   
            count++;
            start--;
            end++;
        }
        
        return count;
    }

第四章:链表

面试题21:删除倒数第k个结点

题目

给你一个链表,请问如何删除链表中的倒数第k个结点?假设链表中结点的总数为n,那么1≤k≤n。要求只能遍历链表一次
例如输入图4.1中(a)的链表,删除倒数第2个结点之后的链表如图4.1中(b)所示。

4.1

图4.1:从链表中删除倒数第2个结点。(a)一个包含6个结点的链表。(b)删除倒数第2个结点(值为5的结点)之后的链表。

参考代码

public ListNode removeNthFromEnd(ListNode head, int n) {
   
    ListNode dummy = new ListNode(0);
    dummy.next = head;

    ListNode front = head, back = dummy;
    for (int i = 0; i < n; i++) {
   
        front = front.next;
    }

    while (front != null) {
   
        front = front.next;
        back = back.next;
    }

    back.next = back.next.next;                    
    return dummy.next;
}

面试题22:链表中环的入口结点

题目

一个链表中包含环,如何找出环的入口结点?从链表的头结点开始沿着next指针进入环的第一个结点为环的入口结点。例如,在图4.3的链表中,环的入口结点是结点3

4.3

图4.3:结点3是链表中环的入口结点

参考代码

public ListNode detectCycle(ListNode head) {
   
    ListNode inLoop = getNodeInLoop(head);
    if (inLoop == null) {
   
        return null;
    }

    ListNode node = head;
    while (node != inLoop) {
   
        node = node.next;
        inLoop = inLoop.next;
    }

    return node;
}

private ListNode getNodeInLoop(ListNode head) {
   
    if (head == null || head.next == null) {
   
        return null;
    }

    ListNode slow = head.next;
    ListNode fast = slow.next;
    while (slow != null && fast != null) {
   
        if (slow == fast)
            return slow;

        slow = slow.next;
        fast = fast.next;
        if (fast != null)
            fast = fast.next;
    }

    return null;
}

面试题23:两个链表的第一个重合结点

题目

输入两个单向链表,请问如何找出它们的第一个重合结点。例如图4.5中的两个链表的第一个重合的结点的值是4

4.5
图4.5:两个部分重合的链表,它们的第一个重合的结点的值是4

参考代码

public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
   
    int count1 = countList(headA);
    int count2 = countList(headB);
    int delta = Math.abs(count1 - count2);
    ListNode longer = count1 > count2 ? headA : headB;
    ListNode shorter = count1 > count2 ? headB : headA;
    ListNode node1 = longer;
    for (int i = 0; i < delta; ++i) {
   
        node1 = node1.next;
    }

    ListNode node2 = shorter;
    while (node1 != node2) {
   
        node2 = node2.next;
        node1 = node1.next;
    }

    return node1;
}

private int countList(ListNode head) {
   
    int count = 0;
    while (head != null) {
   
        count++;
        head = head.next;
    }

    return count;
}

面试题24:反转链表

题目

定义一个函数,输入一个链表的头结点反转该链表并输出反转后链表的头结点。例如,把图4.8(a)中的链表反转之后得到的链表如图4.8(b)所示。

4.8

图4.8:反转一个链表。(a)一个含有5个结点的链表。(b)反转之后的链表。

参考代码

public ListNode reverseList(ListNode head) {
   
    ListNode prev = null;
    ListNode cur = head;    
    while (cur != null) {
   
        ListNode next = cur.next;
        cur.next = prev;
        prev = cur;
        cur = next;
    }

    return prev;
}

面试题25:链表中的数字相加

题目

给你两个表示非负整数的单向链表,请问如何实现这两个整数的相加并且把和仍然用单向链表表示?链表中的每个结点表示整数十进制的一位,并且头结点对应整数的最高位数而尾结点对应整数的个位数。例如在图4.10(a)和(b)中的两个链表分别表示整数123531,它们的和为654,对应的链表尾图4.10的(c)所示。

4.10
图4.10:链表中数字以及它们的和。(a)表示整数123的链表。(b)表示整数531的链表。(c)表示123531的和654的链表。

参考代码

public ListNode addTwoNumbers(ListNode head1, ListNode head2) {
   
    head1 = reverseList(head1);
    head2 = reverseList(head2);
    ListNode reversedHead = addReversed(head1, head2);
    return reverseList(reversedHead);
}

private ListNode addReversed(ListNode head1, ListNode head2) {
   
    ListNode dummy = new ListNode(0);
    ListNode sumNode = dummy;
    int carry = 0;
    while (head1 != null || head2 != null) {
   
        int sum = (head1 == null ? 0 : head1.val)
                + (head2 == null ? 0 : head2.val) + carry;
        carry = sum >= 10 ? 1 : 0;
        sum = sum >= 10 ? sum - 10 : sum;        
        ListNode newNode = new ListNode(sum);

        sumNode.next = newNode;            
        sumNode = sumNode.next;

        head1 = head1 == null ? null : head1.next;
        head2 = head2 == null ? null : head2.next;
    }

    if (carry > 0) {
   
        sumNode.next = new ListNode(carry);
    }

    return dummy.next;
}

private ListNode reverseList(ListNode head) {
   
    ListNode reversedHead = null;
    ListNode prev = null;
    ListNode cur = head;    
    while (cur != null) {
   
        ListNode next = cur.next;
        if (next == null)
            reversedHead = cur;

        cur.next = prev;
        prev = cur;
        cur = next;
    }

    return reversedHead;
}

面试题26:重排链表

题目

给你一个链表,链表中结点的顺序是L0→ L1→ L2→…→ Ln-1→ Ln,请问如何重排链表使得结点的顺序变成L0→ Ln→ L1→ Ln-1→ L2→ Ln-2→…?例如输入图4.12(a)中的链表,重排之后的链表如图4.12(b)所示。

4.12
图4.12:重排链表。(a)一个含有6个结点的链表。(b)重排之后的链表。

参考代码

public void reorderList(ListNode head) {
   
    ListNode dummy = new ListNode(0);
    dummy.next = head;        
    ListNode fast = dummy;
    ListNode slow = dummy;
    while (fast != null && fast.next != null) {
   
        slow = slow.next;
        fast = fast.next;
        if (fast.next != null) {
   
            fast = fast.next;
        }            
    }

    ListNode temp = slow.next;
    slow.next = null;
    link(head, reverseList(temp), dummy);
}

private void link(ListNode node1, ListNode node2, ListNode head) {
   
    ListNode prev = head;
    while (node1 != null && node2 != null) {
   
        ListNode temp = node1.next;

        prev.next = node1;
        node1.next = node2;
        prev = node2;

        node1 = temp;
        node2 = node2.next;
    }

    if (node1 != null) {
   
        prev.next = node1;
    }
}

private ListNode reverseList(ListNode first) {
   
    ListNode prev = null;
    ListNode cur = first;
    ListNode head = null;
    while (cur != null) {
   
        ListNode next = cur.next;
        cur.next = prev;
        if (next == null) {
   
            head = cur;
        }

        prev = cur;
        cur = next;
    }

    return head;
}

面试题27:回文链表

题目

如何判断一个链表是不是回文?要求解法的时间复杂度O(n),另外不得使用超过O(1)辅助空间。如果一个链表是回文,那么链表中结点序列从前往后看和从后往前看是相同的。例如,图4.13中的链表的结点序列从前往后看和从后往前看都是1、2、3、3、2、1,因此这是一个回文链表。

4.13
图4.13:一个回文链表。

参考代码

public boolean isPalindrome(ListNode head) {
   
    if (head == null || head.next == null) {
   
        return true;
    }

    ListNode slow = head;
    ListNode fast = head.next;
    while (fast.next != null && fast.next.next != null) {
   
        fast = fast.next.next;
        slow = slow.next;
    }

    ListNode secondHalf = slow.next;
    if (fast.next != null) {
   
        secondHalf = slow.next.next;
    }

    slow.next = null;
    return equals(secondHalf, reverseList(head));
}

public ListNode reverseList(ListNode head) {
   
    ListNode reversedHead = null;
    ListNode prev = null;
    ListNode cur = head;    
    while (cur != null) {
   
        ListNode next = cur.next;
        if (next == null) {
   
            reversedHead = cur;
        }

        cur.next = prev;
        prev = cur;
        cur = next;
    }

    return reversedHead;
}

面试题28:展平多级双向链表

题目

在一个多级双向链表中节点除了有两个指针分别指向前后两个节点之外,还有一个指针指向它的子链表,并且子链表也是一个双向链表,它的节点也有指向子链表的指针。请将这样的多级双向链表展平成普通的双向链表,即所有节点都没有子链表。例如图4.14(a)是一个多级双向链表,它展平之后如图4.14(b)所示。

4.14
图4.14:展平多级双向链表。(a)一个多级双向链表。(b)展平之后的双向链表。

参考代码

public Node flatten(Node head) {
   
    flattenGetTail(head);
    return head;
}

private Node flattenGetTail(Node head) {
   
    Node node = head;
    Node tail = null;
    while (node != null) {
   
        Node next = node.next;
        if (node.child != null) {
   
            Node child = node.child;
            Node childTail = flattenGetTail(node.child);

            node.child = null;
            node.next = child;
            child.prev = node;
            childTail.next = next;
            

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1368188.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

数字孪生与数据可视化大屏

什么是数字孪生 数字孪生技术是一种在现实世界中模拟虚拟世界的技术,它可以将物理世界中的各种事物、过程、行为等转化为虚拟世界中的数据模型,从而实现虚拟世界与现实世界的互动。数字孪生技术可以应用于能源管理、建筑能耗评估、设备全生命周期管理等领域,它可以帮助企业…

计算机体系结构流水线学习记录

一、知识点汇总 1.理想情况下&#xff0c;流水线能够实现 n 倍的吞吐率加速比&#xff08;n为流水线深度&#xff09;&#xff0c;但是流水线深度并非越大越好&#xff0c;因为流水线的深度会影响到性能和功耗之间的平衡。 2.RISC&#xff1a;Reduced Instruction Set Comput…

WPF真入门教程26--项目案例--欧姆龙PLC通讯工具

1、案例介绍 前面已经完成了25篇的文章介绍&#xff0c;概括起来就是从0开始&#xff0c;一步步熟悉了wpf的概念&#xff0c;UI布局控件&#xff0c;资源样式文件的使用&#xff0c;MVVM模式介绍&#xff0c;命令Command等内容&#xff0c;这节来完成一个实际的项目开发&#…

第57、58颗北斗导航卫星发射成功

第57、58颗北斗导航卫星发射成功&#xff01; 12月26日11时26分&#xff0c;我国在西昌卫星发射中心用长征三号乙运载火箭与远征一号上面级&#xff0c;成功发射第57、58颗北斗导航卫星。 这组卫星属中圆地球轨道卫星&#xff08;MEO卫星&#xff09;&#xff0c;是我国北斗三…

自动计算薪资-全优学堂

功能说明 全优学堂薪资模块则根据基础薪资、历史上课情况、课程销售情况自动计算员工薪资&#xff0c;帮助您更好地进行成本管理。系统根据教职工的排班情况、课时数和提成规则&#xff0c;自动计算教职工的薪资&#xff0c;大大减轻工资管理负担。 #1. 基础薪资配置 设置本…

ASP.NET中小型超市管理系统源码

ASP.NET中小型超市管理系统源码 超市管理系统是专门为中小型超市打造的管理系统&#xff0c;可以方便管理时更加准确清晰的查看商品信息&#xff0c; 仓库出售与进货的信息&#xff0c;还有每一个部门员工的信息&#xff0c;也更加直观的体现出每一阶段的商品销售情况&#xf…

python炒股自动化(0),申请券商API接口

上次发了量化交易接口的区别&#xff0c;发现很多人根本不知道券商提供的API交易接口&#xff0c;这里补充一篇&#xff0c;关于券商接口的介绍。 现在市面上可以给个人账户接入的股票交易接口&#xff0c;用的最多的也就是QMT和Ptrade&#xff0c;以前接入量化交易需要机构或…

【Gin实战教程】快速入门

Gin是一个轻量级的Web框架&#xff0c;使用Go语言开发。它具有高性能、易用性和灵活性的特点&#xff0c;是构建可扩展的Web应用程序的理想选择。 首先&#xff0c;Gin是一个高性能的框架。它基于Go语言的原生HTTP包进行开发&#xff0c;利用了Go语言的并发特性和协程模型&…

避免重复扣款:分布式支付系统的幂等性原理与实践

这是《百图解码支付系统设计与实现》专栏系列文章中的第&#xff08;6&#xff09;篇。 本文主要讲清楚什么是幂等性原理&#xff0c;在支付系统中的重要应用&#xff0c;业务幂等、全部幂等这些不同的幂等方案选型带来的收益和复杂度权衡&#xff0c;幂等击穿场景及可能的严重…

sqlmap性能优化

sqlmap性能优化 &#x1f388;&#x1f388;&#x1f388;&#x1f388;&#x1f388;&#x1f388;&#x1f388;&#x1f388;&#x1f388;&#x1f388;&#x1f388;&#x1f388;&#x1f388;&#x1f388;&#x1f388;&#x1f388;&#x1f32d;&#x1f32d;&#…

【Linux Shell】11. 输入/输出 重定向

文章目录 【 1. 重定向简介 】【 2. 输出重定向 】【 3. 输入重定向 】【 4. Here Document 】【 5. /dev/null 文件 】 【 1. 重定向简介 】 大多数 UNIX 系统命令从终端接受输入并将所产生的输出发送回​​到原来输入的终端。一个命令通常从标准输入的地方读取输入&#xff…

漫谈与人类智能相关数学知识的不足之处

客观地说&#xff0c;没有数学就没有当前的大语言模型、多模态大模型&#xff0c;甚至压根就没有人工智能。对人工智能而言&#xff0c;数学就是“天”&#xff01;但是&#xff0c;对于人类智能而言&#xff0c;数学虽然起到了很重要的作用&#xff0c;同样也起到了阻碍作用&a…

table嵌套table的样式

文章目录 table嵌套的格式table嵌套表格的样式注意 table嵌套注意事项 table嵌套的格式 tr 内嵌table <table><tr><table></table></tr> </table>td内嵌table <table><tr><td><table></table></td>…

ubuntu创建pytorch-gpu的docker环境

文章目录 安装docker创建镜像创建容器 合作推广&#xff0c;分享一个人工智能学习网站。计划系统性学习的同学可以了解下&#xff0c;点击助力博主脱贫( •̀ ω •́ )✧ 使用docker的好处就是可以将你的环境和别人的分开&#xff0c;特别是共用的情况下。本文介绍了ubuntu环境…

【动态规划】C++算法:446等差数列划分 II - 子序列

作者推荐 【动态规划】C算法312 戳气球 446. 等差数列划分 II - 子序列 给你一个整数数组 nums &#xff0c;返回 nums 中所有 等差子序列 的数目。 如果一个序列中 至少有三个元素 &#xff0c;并且任意两个相邻元素之差相同&#xff0c;则称该序列为等差序列。 例如&#…

Developer Tools for Game Creator 1

插件包含: 持久世界时间管理系统 单击以生成对象或预设 游戏内调试控制台 游戏内事件控制台 控制台管理控制 命令模板脚本 游戏内屏幕截图 低分辨率和高分辨率图像 缩略图生成 移动支持 使用Game Creator Action或拖放来激活和控制组件,无需编码。 通过此资产,您可以获得: …

群晖Synology Drive同步文件时过滤指定文件夹“dist“, “node_modules“

群晖Synology Drive同步文件时过滤指定文件夹"dist", “node_modules” mac用户 安装Synology Drive创建同步任务修改Synology Drive配置 打开/Users/[用户名]/Library/Application Support/SynologyDrive/data/session/[同步任务序号&#xff0c;第一个同步任务就…

Python——python编译器安装教程

1.前往python官网下载安装程序 python官网 python编译器安装程序下载网站 2.找到自己需要的版本&#xff0c;下载对应的安装程序&#xff0c;运行程序 打开安装包&#xff0c;切记要勾选add python 3.9 to PATH 可选择自动安装&#xff08;Install Now&#xff09;或点击自定义…

WPF常用控件-Window

常用属性 这里重点记录一些关键且容易忘记的属性&#xff0c;那些很常用的如Title啥的就不在这里一一说明了。 任务栏按钮 ShowInTaskbar&#xff1a;是否在任务栏中显示应用按钮&#xff0c;默认为True。 层级 Topmost&#xff1a;应用是否始终在所有应用的最上层&#x…

Vue2:通过ref获取DOM元素

一、场景描述 我们在页面的开发过程中&#xff0c;经常需要操作dom元素&#xff0c;来实现我们需要的效果。 以往js中&#xff0c;我们是通过给dom添加id&#xff0c;然后&#xff0c;通过js代码document来获取这个dom 简写代码案例&#xff1a; <h2 id"test"&…