剑指Offer题解(持续更新)

第2️⃣章

03 | 数组中重复的数字

问题描述

在一个长度为 n 的数组 nums 里的所有数字都在 0~n-1 的范围内。数组中某些数字是重复的,但不知道有几个数字重复了,也不知道每个数字重复了几次。请找出数组中任意一个重复的数字。

本题特点

  • 数组长度与数组内数组内数字范围宽度

解题思路

  • 把数字i放到num[i]上
  • 如果num[i]上已经有i了,那么就是重复的数字了

代码

class Solution {
    public int findRepeatNumber(int[] nums) {
        int result = -999;
        for (int i = 0; i < nums.length; i++) {
            if (nums[i] == i) { // 已经在自己的位置上
                continue;
            }
            
            // 换到换到自己的位置上,并且将换过来的数也换到自己的位置上,
            while (true) {
                if (nums[i] == nums[nums[i]]) { // 发现自己位置上已经是对的人了。说明重复了
                    return nums[i];
                } else {
                    swap(nums, i, nums[i]);
                }
                if (nums[i] == i) { // i位置上是对的人了
                    break;
                }
            }
        }
        return result;
    }

    private void swap(int[] nums, int x, int y) {
        int temp = nums[x];
        nums[x] = nums[y];
        nums[y] = temp;
    }
}

其他方法分析

方法时间复杂度空间复杂度
题解方法O(n)O(1)
哈希表O(n)O(n)
先排序后遍历数组O(nlogn)O(1)
二分法O(nlogn)O(1)不会修改原数组

若果不允许修改数组呢?(二分法,详情见书,时间复杂度O(nlogn))

04 | 二维数组中的查找

问题描述

在一个 n * m 的二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。

解题思路

  • 数组右上角(或者左下角)的元素很特殊,该元素的行中它是最大的,列中它是最小的
  • 所以可以将target与它比较
    • 若等于,则返回true
    • 若martix[右上] < target,则martix[右上]左侧比它还要小的一行就不用考虑了
    • 若martix[右上] > target,则martix[右上]下侧比它还要大的一列就不用考虑了
  • 一行/一列被去掉后会出现新的martix[右上],继续判断直至没有元素可以比较

代码

class Solution {
    public boolean findNumberIn2DArray(int[][] matrix, int target) {
        // 空数组
        if (matrix.length == 0) {
            return false;
        }

        int x = 0;
        int y = matrix[0].length - 1;

        while (x != matrix.length && y != -1) {
            int cur = matrix[x][y];
            if (target == cur) {
                return true;
            } else if (target > cur) {
                x++;
            } else {
                y--;
            }
        }
        return false;
    }
}

05 | 替换空格

问题描述

请实现一个函数,把字符串 s 中的每个空格替换成"%20"。

原题为c题目,在java中这题没有背景

解题思路

  • 第一次遍历计算空格数量
  • 第二次从尾到头移动数组

06 | 从尾到头打印链表

问题描述

输入一个链表的头节点,从尾到头反过来返回每个节点的值(用数组返回)。

解题思路(3种)

  1. 栈栈
  2. 递归
  3. 翻转链表

代码

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
class Solution {
    //反转链表:快,但是会更改链表结构
    public int[] reversePrint(ListNode head) {
        ListNode cur = head, prev = null, next;
        int count = 0;
        while (cur != null) {
            count++;
            next = cur.next;
            cur.next = prev;
            prev = cur;
            cur = next;
        }

        int[] ans = new int[count];
        cur = prev;
        for (int i = 0; cur != null; i++) {
            ans[i] = cur.val;
            cur = cur.next;
        }

        return ans;
    }


    //栈
    // Stack<Integer> stack = new Stack<>();

    // public int[] reversePrint(ListNode head) {
    //     while (head != null) {
    //         stack.push(head.val);
    //         head = head.next;
    //     }
        

    //     int[] ans = new int[stack.size()];
    //     for(int i = 0; i < ans.length; i++){
    //         ans[i] = stack.pop();
    //     }

    //     return ans;
    // }


    //递归:很巧妙但是很慢
    // ArrayList<Integer> ans = new ArrayList<>();

    // public int[] reversePrint(ListNode cur) {
    //     if (cur != null){
    //         reversePrint(cur.next);
    //         ans.add(cur.val);
    //     }
        
    //     int[] arr = new int[ans.size()];
    //     for (int i = 0; i < arr.length; i++) {
    //         arr[i] = ans.get(i);
    //     }
    //     return arr;
    // }
}

07 | 重建二叉树

问题描述

输入某二叉树的前序遍历和中序遍历的结果,请重建该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。

解题思路

  • 通过手工画图重建,想到肯能是递归
  • 前序遍历:根左右;中序遍历:左根右,可以得出
    • 前序的第一个节点为根节点
    • 中序中根以左的是根的左子树的中序;根以右的是根的右子树的中序
    • 前序中除根以外的,“左”“右”混合在一起,单凭前序无法区分,但是可以通过统计中序中根以左的个数来区分前序中的“左”“右”
    • 至此已经可以通过一个前序和中序得出:1.根 2.左子树和右子树的前序和中序
    • 开始递归

代码

class Solution {
    HashMap<Integer, Integer> indexMap = new HashMap<>();

    public TreeNode buildTree(int[] preorder, int[] inorder) {
        // 建立<节点val,中序数组下标>的哈希索引
        for (int i = 0; i < inorder.length; i++) {
            indexMap.put(inorder[i], i);
        }

        TreeNode result = myBuildTree(preorder, inorder, 0 , preorder.length-1, 0, inorder.length-1);
        return result;
    }

    // 方法参数分别为:
    // preOrder、inOrder:完整的前序中序数组
    // preOrderLeft、preOrderRight:前序数组的左右届
    // inOrderLeft、inOrderRight:中序数组的左右届
    private TreeNode myBuildTree (int[] preOrder, int[] inOrder, int preOrderLeft, int preOrderRight, int inOrderLeft, int inOrderRight) {
        // 这个判断条件还没有搞明白,2021年6月28日
        if (preOrderLeft > preOrderRight) {
            return null;
        }

        // 通过前序的第一个值拿到根节点的值
        int rootVal = preOrder[preOrderLeft];
        // 通过该值拿到根节点在中序中的位置
        int rootIndex = indexMap.get(rootVal);
        // 中序中根以左全部为该根的左子树,计算节点个数,以从得到先序中右子树开始的位置
        int len = rootIndex - inOrderLeft;
		
        // 说起来比较麻烦..找个不是特别简单的前序和中序,h
        TreeNode root = new TreeNode(rootVal);
        root.left = myBuildTree(preOrder, inOrder, preOrderLeft + 1, preOrderLeft + len, inOrderLeft, rootIndex - 1);
        root.right = myBuildTree(preOrder, inOrder, preOrderLeft + len + 1, preOrderRight, rootIndex + 1, inOrderRight);

        return root;
    }
}

09 | 用两个栈实现队列

问题描述

用两个栈实现一个队列。队列的声明如下,请实现它的两个函数 appendTail 和 deleteHead ,分别完成在队列尾部插入整数和在队列头部删除整数的功能。(若队列中没有元素,deleteHead 操作返回 -1 )

解题思路

  • 可以想象两个区域,排队区进入区
  • 入队的元素先进入排队区,出队的元素从进入区选择
  • 当即将进如区为空时,将排队区的元素全部依次进入进入区(即先进去排队区的,先出进入区(将栈倒置即可))

代码

class CQueue {
    Stack<Integer> s1 = new Stack<>();
    Stack<Integer> s2 = new Stack<>();

    public CQueue() {

    }
    
    public void appendTail(int value) {
        s1.push(value);
    }
    
    public int deleteHead() {
        if (s1.empty() && s2.empty()) {
            return -1;
        }

        if (!s2.empty()) {
            return s2.pop();
        }
        
        while (!s1.empty()) {
            s2.push(s1.pop());
        }
        return s2.pop();
    }
}

相关题目-225. 用两个队列实现栈

10 | 斐波那契数列/青蛙跳台阶

问题描述

一只青蛙一次可以跳上1级台阶,也可以跳上2级台阶。求该青蛙跳上一个 n 级的台阶总共有多少种跳法。

解题思路

  • 可以把不同的问题化解成相同的问题
  • 跳台阶注意初始条件即可:f(1)= 1,f(2) = 2

代码

class Solution {
    public int fib(int n) {
        if (n == 0) return 0;
        if (n == 1) return 1;

        int fibNM2 = 0;
        int fibNM1 = 1;
        int fibN = -99;

        for (int i = 2; i <= n; i++) {
            fibN = (fibNM1 + fibNM2) % 1000000007;
            fibNM2 = fibNM1;
            fibNM1 = fibN;
        }

        return fibN;
    }


    // int[] fib = new int[101];

    // public int fib(int n) {
    //     if (n == 0) return 0;
    //     if (n == 1) return 1;
    //     if (fib[n] != 0) return fib[n];

    //     int ans = (fib(n-1) + fib(n-2)) % 1000000007;
    //     fib[n] = ans;
    //     return ans;
    // }
}

11 | 旋转数组的最小数字

题目描述

把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。输入一个递增排序的数组的一个旋转,输出旋转数组的最小元素。例如,数组 [3,4,5,1,2] 为 [1,2,3,4,5] 的一个旋转,该数组的最小值为1。

解题思路

  • 三种情况

    1. 数组中只有一个元素,直接返回该元素

    2. 数组最开始的 0或数组长度的倍数 个元素搬到数组的末尾,也就是还是原数组

      • 如果第一个numbers[0] < numbers[numbers.length - 1]就是这种情况,直接返回numbers[0]
    3. 正常的经过旋转与原数组不同的数组,这样的数组有一个特征:以最小值为分界点,分为两个单调递增的数组

      • 左侧数组 >= 右侧数组,所以比q大的mid位于左侧数组,比q小的mid位于右侧数组
      • 通过二分法一次排除掉一半的元素,直至p + 1 = q,此时numbers[q]为最小值
      • 其中特例:当p、q、mid相等时,无法判断mid处于哪个数组,采用普通方法解决

代码

class Solution {
    public int minArray(int[] numbers) {
        int p = 0;
        int q = numbers.length - 1;
        int mid;
		
        // 数组中只有一个元素
        if (p == q) {
            return numbers[p];
        }
		
        // 未经旋转的数组,或旋转后与原数组相同,单调递增
        if(numbers[p] < numbers[q]) {
            return numbers[p];
        }
		
        // p、q会慢慢靠近分界点的,pq挨着时,numbers[q]为最小值
        while (q - p != 1) {
            mid = (p + q) / 2;
            // p q mid相等时,无法判断mid处于哪个数组,采用普通方法解决
            if (numbers[p] == numbers[q] && numbers[q] == numbers[mid]) {
                return min(numbers, p, q);
            }
			
            // 二分法
            // 左侧数组 >= 右侧数组,所以比q大的mid位于左侧数组,比q小的mid位于右侧数组
            if (numbers[mid] >= numbers[p]) {
                p = mid;
            } else if (numbers[mid] <= numbers[q]) {
                q = mid;
            }
        }
        return numbers[q];
    }

    private int min(int[] numbers, int p, int q) {
        int last = numbers[q];
        int cur;
        for (int i = p; i <= q; i++) {
            cur = numbers[i];
            if (cur < last) {
                return cur;
            }
            last = cur;
        }
        // 都相等的情况
        return last;
    }
}

12 | 矩阵中的路径

问题描述

给定一个 m x n 二维字符网格 board 和一个字符串单词 word 。如果 word 存在于网格中,返回 true ;否则,返回 false 。

单词必须按照字母顺序,通过相邻的单元格内的字母构成,其中“相邻”单元格是那些水平相邻或垂直相邻的单元格。同一个单元格内的字母不允许被重复使用

例如,在下面的 3×4 的矩阵中包含单词 “ABCCED”(单词中的字母已标出)。

解题思路

  • 深搜,失败就回溯

代码

class Solution {
    boolean[][] visited;
    int m;
    int n;

    public boolean exist(char[][] board, String word) {
        m = board.length;
        n = board[0].length;
        visited  = new boolean[m][n];
        // 要找的是第几个字符
        int num;
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                // 每一个格子都可能是起点
                num = 0; // 重置num
                if (isOk(board, word, i, j, num, "init")) {
                    return true;
                }
            }
        }
        return false;
    }

    private boolean isOk(char[][] board, String word, int p, int q, int num, String mod) {
        if (mod == "up") {
            p--;
        } else if (mod == "down") {
            p++;
        } else if (mod == "left") {
            q--;
        } else if (mod == "right") {
            q++;
        }

        // 越界、不是要找的字母、已访问
        if (p < 0 || p > m - 1 || q < 0 || q > n - 1 || board[p][q] != word.charAt(num) || visited[p][q] == true) {
            return false;
        } else { // 如果这个格子ok,那么需要看下他周围下一个字符
            // 找下一个字符
            num++;
            // 如果找完了
            if (num == word.length()) {
                return true;
            }
            // 标记当前格子是ok的
            visited[p][q] = true;
            // 周围是否有ok的格子
            boolean isOk = isOk(board,word,p,q,num,"up") || isOk(board,word,p,q,num,"down") 
            || isOk(board,word,p,q,num,"left") || isOk(board,word,p,q,num,"right");
            // 有两种情况会执行下面这句:1.周围4个格子都不符合要求,那么当前格子也就不符合要求了,回溯;2.成功,一路true返回,这是不执行这就也没事
            visited[p][q] = false;
            return isOk;
        }
    }
}

13. | 机器人的运动范围

问题描述

地上有一个m行n列的方格,从坐标 [0,0] 到坐标 [m-1,n-1] 。一个机器人从坐标 [0, 0] 的格子开始移动,它每次可以向左、右、上、下移动一格(不能移动到方格外),也不能进入行坐标和列坐标的数位之和大于k的格子。例如,当k为18时,机器人能够进入方格 [35, 37] ,因为3+5+3+7=18。但它不能进入方格 [35, 38],因为3+5+3+8=19。请问该机器人能够到达多少个格子?

解题思路

  • dfs
  • 去过的地方用visited[][]标记
  • 根据本题的神秘规律,只需向下和向右探索即可得到所有解

代码

class Solution {
    int count = 0;
    int m, n, k;
    boolean[][] visited;

    public int movingCount(int m, int n, int k) {
        this.m = m;
        this.n = n;
        this.k = k;
        this.visited = new boolean[m][n];
        // dfs
        canMoveTo(0, 0);
        return count;
    }

    private void canMoveTo(int p, int q) {
        if (p > m - 1 || q > n - 1 || visited[p][q] == true || sum(p) + sum(q) > k) {
            return;
        } else {
            visited[p][q] = true;
            count++;
            // 只向右和向下
            canMoveTo(p + 1, q);
            canMoveTo(p, q + 1);
        }
    }

    private int sum (int num) {
        int sum = 0;
        sum += num / 10;
        sum += num % 10;
        return sum;
    }
}

14| 剪绳子|剪绳子 II

问题描述

给你一根长度为 n 的绳子,请把绳子剪成整数长度的 m 段(m、n都是整数,n>1并且m>1),每段绳子的长度记为 k[0],k[1]…k[m - 1] 。请问 k[0]k[1]…*k[m - 1] 可能的最大乘积是多少?例如,当绳子的长度是8时,我们把它剪成长度分别为2、3、3的三段,此时得到的最大乘积是18。

Ⅱ:答案需要取模 1e9+7(1000000007),如计算初始结果为:1000000008,请返回 1。

解题思路

  • 动态规划
    • 自下而上
  • 贪心

代码

class Solution {
    public int cuttingRope(int n) {
        if (n == 2) {
            return 1;
        }
        if (n == 3) {
            return 2;
        }

        int[] products  = new int[n + 1];
        int max;
        products[2] = 2;
        products[3] = 3;

        for (int i = 4; i <= n; i++) {
            max = 0;
            for (int j = 2; j <= i / 2; j++) {
                max = Math.max(max, products[j] * products[i - j]);
            }
            products[i] = max;
        }

        return products[n];
    }
}

15 | 二进制中1的个数

问题描述

请实现一个函数,输入一个整数,输出该数二进制表示中 1 的个数。例如,把 9表示成二进制是 1001,有 2 位是 1。因此,如果输入 9,则该函数输出 2。

解题思路

  • 方法1:
    • 循环检测法:将n与1、100、1000…(二进制)做&运算,若不等于0,可以证明该位为1
  • 方法2:
    • 将二进制数 -1 即可将二进制数最低位的 1 置位 0 ,比该 1 位数还低的 0 置位 1,如1100 - 1 = 1011
    • 将 -1 后的数与原数作 & 操作,即可将原数中最低位的 1 去除

代码

public class Solution {
    // 循环检测二进制位
    public int hammingWeight(int n) {
        int count = 0;
        for (int i = 0; i < 32; i++) {
            if ((n & 1 << i) != 0) {
                count++;
            }
        }
        return count;
    }
}
public class Solution {
    // 技巧:n & (n - 1)可以去掉最右边的0
    public int hammingWeight(int n) {
        int count = 0;
        while (n != 0) {
            count ++;
            n = n & (n - 1); 
        }
        return count;
    }
}

第3️⃣章

16 | 数值的整数次方

问题描述

实现 pow(x, n) ,即计算 x 的 n 次幂函数(即,xn)。不得使用库函数,同时不需要考虑大数问题。

解题思路

快速幂

代码

class Solution {
    public double myPow(double x, int n) {
        double result;
		// 1的任何次幂还是1
        if (Double.compare(x, 1.0) == 0) return x;
        // 任何数的1次幂还是本身
        if (n == 1) return x;
        // 任何数的0次幂是1
        if (n == 0) return 1;
        
        int oldn = n;
        // 指数小于1就转化一下
        if (n < 0) {
            x = 1/x;
            // 特殊情况:对Integer.MIN_VALUE取负取绝对值都还是Integer.MIN_VALUE
            // Integer.MAX_VALUE == 2147483647
        	// Integer.MIN_VALUE == -2147483648
            // 后面需要补一次乘法
            if (n == Integer.MIN_VALUE) {
                n = Integer.MAX_VALUE;
            } else {
                n = -n;
            }
            
        }

        result = fastPow(x, n);
        if (oldn == Integer.MIN_VALUE) {
            result *= x;
        }
        return result;
    }

    // 快速幂
    private double fastPow(double x, int n) {
        if (n == 1) {
            return x;
        }
        double result;
        result = fastPow(x, n >> 1);
        result = result * result;
        if((n & 1) == 1) {
             result *= x;
        }
        return result;
    }
}

22 | 链表中倒数第k个节点

题目描述

输入一个链表,输出该链表中倒数第k个节点。为了符合大多数人的习惯,本题从1开始计数,即链表的尾节点是倒数第1个节点。例如,一个链表有6个节点,从头节点开始,它们的值依次是1、2、3、4、5、6。这个链表的倒数第3个节点是值为4的节点。

解题思路

  • 双指针
  • 倒数第k个节点,与倒数第1个节点相差k-1步
  • 设置双指针初始为起点,让j先走k-1步,此时i与j的距离倒k节点与倒1节点距离相等
  • 将i,j同时后移直至j抵达链表末尾即可

代码

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
class Solution {
    public ListNode getKthFromEnd(ListNode head, int k) {
        ListNode i = head,j = head;
        for (int m = 0; m < k-1; m++) {
            j = j.next;
        }

        while (j.next != null) {
            i = i.next;
            j = j.next;
        }
        
        return i;
    }
}

24 | 反转链表

问题描述

定义一个函数,输入一个链表的头节点,反转该链表并输出反转后链表的头节点。

解题思路

太简单

代码

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
class Solution {
    public ListNode reverseList(ListNode head) {
        ListNode cur = head, next, prev = null;
        while (cur != null) {
            next = cur.next;
            cur.next = prev;
            prev = cur;
            cur = next;
        }
        return prev;
    }
}

第4️⃣章

30 | 包含min函数的栈

问题描述

定义栈的数据结构,请在该类型中实现一个能够得到栈的最小元素的 min 函数在该栈中,调用 min、push 及 pop 的时间复杂度都是 O(1)。

解题思路

  • 栈顶元素为最小元素时,若进行出栈操作,则需要对栈内所有元素进行比较,复杂度:O(N)
  • 使用辅助栈来存储各个时刻栈内的最小元素

代码

class MinStack {

    Stack<Integer> stack = new Stack<>();
    Stack<Integer> auxStack = new Stack<>();


    /** initialize your data structure here. */
    public MinStack() {

    }
    
    public void push(int x) {
        stack.push(x);
        if (auxStack.empty() || x < auxStack.peek()) {
            auxStack.push(x);
        } else {
            auxStack.push(auxStack.peek());
        }
    }
    
    public void pop() {
        stack.pop();
        auxStack.pop();
    }
    
    public int top() {
        return stack.peek();
    }
    
    public int getMin() {
        return auxStack.peek();
    }
}

第5️⃣章

39 | 数组中出现次数超过一半的数字

题目描述

数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。你可以假设数组是非空的,并且给定的数组总是存在多数元素。

解题思路

  1. 摩尔投票法
    • 如果两个数不相同就让他们抵消,会分为两种情况(其中包含众数,与其中不包含众数),但无论哪种情况,数组中剩余元素的众数 与 原先众数还是一样的。
    • 可以拓展为:数组中连续的2*k个元素,若其中有一半(k个)元素是相同的,则他们可以和另一半(k个)抵消。
  2. xxxx

代码

//摩尔投票法
class Solution {
    public int majorityElement(int[] nums) {
        int count = 0;
        int ans = 0;

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

52 | 两个链表的第一个公共节点

问题描述

输入两个链表,找出它们的第一个公共节点。

解题思路

  • 则设A链表与B链表不相交的部分为a和b,相交的部分(若有)为c
  • 若相交则 a + c + b == b + c + a,若不相交则 a + b == b + a
  • 可见若将A的尾与B的头连,B的尾与A的头连,则两链表会在某一时刻相交(或都为null)

代码

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) {
 *         val = x;
 *         next = null;
 *     }
 * }
 */
public class Solution {
    public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
        ListNode a = headA, b = headB;
        while (a != b) {
            if (a == null) {
                a = headB;
            } else {
                a = a.next;
            }

            if (b == null) {
                b = headA;
            } else {
                b = b.next;
            }
        }

        if (a == null) {
            return null;
        } else {
            return a;
        }
    }
}

第6️⃣章

57 | 和为s的两个数字

题目描述

输入一个递增排序的数组和一个数字s,在数组中查找两个数,使得它们的和正好是s。如果有多对数字的和等于s,则输出任意一对即可。

解题思路

  • 少了就加一点,多了就减一点

代码

class Solution {
    public int[] twoSum(int[] nums, int target) {
        int i = 0, j = nums.length - 1;
        int sum = 0;
        while (true) {
            sum = nums[i] + nums[j];
            if (sum == target) {
                break;
            } else if (sum < target){
                i++;
            } else {
                j--;
            }
        }
        return new int[]{nums[i],nums[j]};
    }
}

57-II | 和为s的连续正数序列

题目描述

输入一个正整数 target ,输出所有和为 target 的连续正整数序列(至少含有两个数)。
序列内的数字由小到大排列,不同序列按照首个数字从小到大排列。

解题思路

  • 少了就加一点,多了就减一点

代码

class Solution {
    public int[][] findContinuousSequence(int target) {
        int i = 1,j = 2;
        int sum = 3;
        ArrayList<int[]> ans = new ArrayList<>();
        while (i <= target/2)
        {
            if (sum > target) {
                sum -= i;
                i++;
            } else if (sum < target){
                j++;
                sum += j;
            }

            if (sum == target) {
                int[] temp = new int[j-i+1];
                for (int k = i; k <= j; k++){
                    temp[k-i] = k;
                }

                ans.add(temp);
                
                sum -= i;
                i++;
            }
        }
        return ans.toArray(new int[ans.size()][]);
    
    }
}

第7️⃣章

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值