202.快乐数

目标

编写一个算法来判断一个数 n 是不是快乐数。

「快乐数」 定义为:

  • 对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和。
  • 然后重复这个过程直到这个数变为 1,也可能是 无限循环 但始终变不到 1。
  • 如果这个过程 结果为 1,那么这个数就是快乐数。

如果 n 是 快乐数 就返回 true ;不是,则返回 false 。

示例 1:

输入:n = 19
输出:true
解释:
12 + 92 = 82
82 + 22 = 68
62 + 82 = 100
12 + 02 + 02 = 1

示例 2:

输入:n = 2
输出:false

提示:

1 <= n <= 2^31 - 1

思路

难点是如何确定停止条件,我甚至想过记录循环次数如果超过某一个数就返回false。我意识到这可能是一个数学问题,就放弃了。

看了题解才明白,问题看似是开放的,但也是有规律的,关键是如何分析这个问题。

考虑最终可能出现的情况:

  • 最终会得到 1。
  • 最终会进入循环。
  • 值会越来越大,最后接近无穷大。

考虑不同位数数字的最大值,进行一次计算的结果:

位数 最大值 下一个值
1 9 81
2 99 162
3 999 243
4 9999 324
13 9999999999999 81*13=1053

相应位上小于最大值的数字,其下一个值也必定小于最大值的下一个值。

意识到存在循环是很重要的,然后我们可以使用哈希表记录出现过的元素,也可以使用弗洛伊德循环检测算法(Floyd's Cycle-Finding Algorithm)又称为龟兔赛跑算法(Tortoise and Hare Algorithm),注意不是图论中求最短路径的弗洛伊德算法。

// todo 自己实现一下

代码

/**
 * @date 2024-06-15 20:59
 */
public class IsHappy202 {

    /**
     * 快慢指针,也是用来检测链表中是否存在环
     * 快慢如果相遇就说明存在环,否则快的先遇到1
     */
    class Solution_v1 {
        public int getNext(int n) {
            int totalSum = 0;
            while (n > 0) {
                int d = n % 10;
                n = n / 10;
                totalSum += d * d;
            }
            return totalSum;
        }

        public boolean isHappy(int n) {
            int slowRunner = n;
            int fastRunner = getNext(n);
            while (fastRunner != 1 && slowRunner != fastRunner) {
                slowRunner = getNext(slowRunner);
                fastRunner = getNext(getNext(fastRunner));
            }
            return fastRunner == 1;
        }
    }

    /**
     * Set记录每次的数字,如果重复就返回false
     */
    class Solution {
        private int getNext(int n) {
            int totalSum = 0;
            while (n > 0) {
                int d = n % 10;
                n = n / 10;
                totalSum += d * d;
            }
            return totalSum;
        }

        public boolean isHappy(int n) {
            Set<Integer> seen = new HashSet<>();
            while (n != 1 && !seen.contains(n)) {
                seen.add(n);
                n = getNext(n);
            }
            return n == 1;
        }
    }

    /**
     * 实际上只会存在一个循环4→16→37→58→89→145→42→20→4
     */
    private static Set<Integer> cycleMembers =
        new HashSet<>(Arrays.asList(4, 16, 37, 58, 89, 145, 42, 20));

    public int getNext(int n) {
        int totalSum = 0;
        while (n > 0) {
            int d = n % 10;
            n = n / 10;
            totalSum += d * d;
        }
        return totalSum;
    }

    public boolean isHappy(int n) {
        while (n != 1 && !cycleMembers.contains(n)) {
            n = getNext(n);
        }
        return n == 1;
    }

}

性能

2806.取整购买后的账户余额

目标

一开始,你的银行账户里有 100 块钱。

给你一个整数purchaseAmount ,它表示你在一次购买中愿意支出的金额。

在一个商店里,你进行一次购买,实际支出的金额会向 最近 的 10 的 倍数 取整。换句话说,你实际会支付一个 非负 金额 roundedAmount ,满足 roundedAmount 是 10 的倍数且 abs(roundedAmount - purchaseAmount) 的值 最小 。

如果存在多于一个最接近的 10 的倍数,较大的倍数 是你的实际支出金额。

请你返回一个整数,表示你在愿意支出金额为 purchaseAmount 块钱的前提下,购买之后剩下的余额。

注意: 0 也是 10 的倍数。

示例 1:

输入:purchaseAmount = 9
输出:90
解释:这个例子中,最接近 9 的 10 的倍数是 10 。所以你的账户余额为 100 - 10 = 90 。

示例 2:

输入:purchaseAmount = 15
输出:80
解释:这个例子中,有 2 个最接近 15 的 10 的倍数:10 和 20,较大的数 20 是你的实际开销。
所以你的账户余额为 100 - 20 = 80 。

说明:

  • 0 <= purchaseAmount <= 100

思路

给我们100块钱购买商品,实际支出的金额需要四舍五入,例如商品金额为4,实际支付为0;商品金额为15,则需要支付20。求我们购物后的余额是多少。

回顾以下API:

  • Math.ceil 向上取整
  • Math.floor 向下取整
  • Math.round 四舍五入

如果我们不使用以上API的话如何实现呢?我们知道整数除法会舍去小数位,即向下取整的,因此我们可以将商品金额加5,如果需要支付的金额个位数大于等于5,加5之后会进位,而如果小于5,除法运算后也没影响。

官网题解还给出了分类讨论个位数的解法,先对10求余,如果余数小于5就舍去,否则就补到10进位。

代码

/**
 * @date 2024-06-12 8:39
 */
public class AccountBalanceAfterPurchase2806 {

    /**
     * 官网还有一种解法,分类讨论
     */
    public int accountBalanceAfterPurchase_v2(int purchaseAmount) {
        int r = purchaseAmount % 10;
        if (r < 5) {
            purchaseAmount -= r;
        } else {
            purchaseAmount += 10 - r;
        }
        return 100 - purchaseAmount;
    }

    /**
     * 网友题解,不使用Math库
     */
    public int accountBalanceAfterPurchase_v1(int purchaseAmount) {
        return 100 - (purchaseAmount + 5) / 10 * 10;
    }

    public int accountBalanceAfterPurchase(int purchaseAmount) {
        return 100 - (int) Math.round(purchaseAmount / 10.0) * 10;
    }

}

性能

3038.相同分数的最大操作数目I

目标

给你一个整数数组 nums ,如果 nums 至少 包含 2 个元素,你可以执行以下操作:

  • 选择 nums 中的前两个元素并将它们删除。

一次操作的 分数 是被删除元素的和。

在确保 所有操作分数相同 的前提下,请你求出 最多 能进行多少次操作。

请你返回按照上述要求 最多 可以进行的操作次数。

示例 1:

输入:nums = [3,2,1,4,5]
输出:2
解释:我们执行以下操作:
- 删除前两个元素,分数为 3 + 2 = 5 ,nums = [1,4,5] 。
- 删除前两个元素,分数为 1 + 4 = 5 ,nums = [5] 。
由于只剩下 1 个元素,我们无法继续进行任何操作。

示例 2:

输入:nums = [3,2,6,1,4]
输出:1
解释:我们执行以下操作:
- 删除前两个元素,分数为 3 + 2 = 5 ,nums = [6,1,4] 。
由于下一次操作的分数与前一次不相等,我们无法继续进行任何操作。

说明:

  • 2 <= nums.length <= 100
  • 1 <= nums[i] <= 1000

思路

按照题目模拟即可。

代码

/**
 * @date 2024-06-07 0:00
 */
public class MaxOperations3038 {
    public int maxOperations(int[] nums) {
        int cnt = 1;
        int n = nums.length;
        int i = 2;
        int score = nums[0] + nums[1];
        while (i < n - 1) {
            int tmp = nums[i] + nums[i + 1];
            if (tmp == score) {
                i += 2;
                cnt++;
            } else {
                break;
            }
        }
        return cnt;
    }
}

性能

1103.分糖果II

目标

排排坐,分糖果。

我们买了一些糖果 candies,打算把它们分给排好队的 n = num_people 个小朋友。

给第一个小朋友 1 颗糖果,第二个小朋友 2 颗,依此类推,直到给最后一个小朋友 n 颗糖果。

然后,我们再回到队伍的起点,给第一个小朋友 n + 1 颗糖果,第二个小朋友 n + 2 颗,依此类推,直到给最后一个小朋友 2 * n 颗糖果。

重复上述过程(每次都比上一次多给出一颗糖果,当到达队伍终点后再次从队伍起点开始),直到我们分完所有的糖果。注意,就算我们手中的剩下糖果数不够(不比前一次发出的糖果多),这些糖果也会全部发给当前的小朋友。

返回一个长度为 num_people、元素之和为 candies 的数组,以表示糖果的最终分发情况(即 ans[i] 表示第 i 个小朋友分到的糖果数)。

示例 1:

输入:candies = 7, num_people = 4
输出:[1,2,3,1]
解释:
第一次,ans[0] += 1,数组变为 [1,0,0,0]。
第二次,ans[1] += 2,数组变为 [1,2,0,0]。
第三次,ans[2] += 3,数组变为 [1,2,3,0]。
第四次,ans[3] += 1(因为此时只剩下 1 颗糖果),最终数组变为 [1,2,3,1]。

示例 2:

输入:candies = 10, num_people = 3
输出:[5,2,3]
解释:
第一次,ans[0] += 1,数组变为 [1,0,0]。
第二次,ans[1] += 2,数组变为 [1,2,0]。
第三次,ans[2] += 3,数组变为 [1,2,3]。
第四次,ans[0] += 4,最终数组变为 [5,2,3]。

说明:

  • 1 <= candies <= 10^9
  • 1 <= num_people <= 1000

思路

现在有一些糖果要分给一排小朋友,第一个小朋友分1个,第二个分2个,依次类推,即分配的糖果总比上一次分的多一个,如果不够就剩多少分多少。如果一轮下来没有分完,就接着从第一个小朋友开始依次分配。问最终每个小朋友能够分得的糖果数量。

我们可以很容易地模拟这个分配过程,记录当前分配的糖果数量,并计算剩余糖果数量直到0。

网友最快的题解使用了数学公式,使时间复杂度从O(num_people+sqrt(candies)) 降为O(num_people)。

代码

/**
 * @date 2024-06-03 0:06
 */
public class DistributeCandies1103 {

    public int[] distributeCandies_v1(int candies, int num_people) {
        int[] res = new int[num_people];
        // 足量发放人次,解不等式:(n+1)n/2 <= candies
        int n = (int) ((Math.sqrt(candies * 8F + 1) - 1) / 2);
        // 足量发放的糖果数量,num_people <= 1000,其实不会溢出
        int distributed = (int) ((1L + n) * n / 2);
        // 剩余糖数量
        int remainder = candies - distributed;
        // 所有小朋友都得到糖果的轮次
        int allGetLoops = n / num_people;
        // 最后一轮获得糖果的人数
        int lastLoopNum = n % num_people;
        for (int i = 0; i < num_people; i++) {
            // 收到糖果的次数 = 所有小朋友都得到糖果的轮次 + 最后一轮是否发放
            int times = (lastLoopNum > i ? 1 : 0) + allGetLoops;
            // 等差数列求和,公差为 num_people,a1 = i + 1,n = times;
            res[i] = ((times - 1) * num_people + i * 2 + 2) * times / 2;
        }
        // 如果是最后一个,将剩余的全部分配
        res[lastLoopNum] += remainder;
        return res;
    }

    public int[] distributeCandies(int candies, int num_people) {
        int[] res = new int[num_people];
        int cnt = 1;
        while (candies > 0) {
            for (int i = 0; i < num_people && candies > 0; i++) {
                int num = Math.min(cnt++, candies);
                candies -= num;
                res[i] += num;
            }
        }
        return res;
    }

}

性能

575.分糖果

目标

Alice 有 n 枚糖,其中第 i 枚糖的类型为 candyType[i] 。Alice 注意到她的体重正在增长,所以前去拜访了一位医生。

医生建议 Alice 要少摄入糖分,只吃掉她所有糖的 n / 2 即可(n 是一个偶数)。Alice 非常喜欢这些糖,她想要在遵循医生建议的情况下,尽可能吃到最多不同种类的糖。

给你一个长度为 n 的整数数组 candyType ,返回: Alice 在仅吃掉 n / 2 枚糖的情况下,可以吃到糖的 最多 种类数。

示例 1:

输入:candyType = [1,1,2,2,3,3]
输出:3
解释:Alice 只能吃 6 / 2 = 3 枚糖,由于只有 3 种糖,她可以每种吃一枚。

示例 2:

输入:candyType = [1,1,2,3]
输出:2
解释:Alice 只能吃 4 / 2 = 2 枚糖,不管她选择吃的种类是 [1,2]、[1,3] 还是 [2,3],她只能吃到两种不同类的糖。

示例 3:

输入:candyType = [6,6,6,6]
输出:1
解释:Alice 只能吃 4 / 2 = 2 枚糖,尽管她能吃 2 枚,但只能吃到 1 种糖。

说明:

  • n == candyType.length
  • 2 <= n <= 10^4
  • n 是一个偶数
  • -10^5 <= candyType[i] <= 10^5

思路

统计糖果种类,然后与n/2比较,取其中的最小值。

可以使用 HashSet 来计算种类数量,题解中最快的解法是自定义了hash函数,将种类映射到数组下标,通过判断相应位置上的值来计数。

代码

/**
 * @date 2024-06-02 9:26
 */
public class DistributeCandies575 {

    public int distributeCandies(int[] candyType) {
        int n = candyType.length;
        Set<Integer> set = new HashSet<>();
        for (int i = 0; i < n; i++) {
            set.add(candyType[i]);
        }
        return Math.min(set.size(), n / 2);
    }

    public int distributeCandies_v1(int[] candyType) {
        int res = 0;
        int n = candyType.length;
        byte[] mask = new byte[200001];
        for (int i = 0; i < n; i++) {
            int c = candyType[i];
            // 由于类型可能为负数,所以使用c+100000
            if (mask[c + 100000] == 0) {
                mask[c + 100000] = 1;
                res++;
                if (res > n / 2) return n / 2;
            }
        }
        return res;
    }
}

性能

2928.给小朋友们分糖果I

目标

给你两个正整数 n 和 limit 。

请你将 n 颗糖果分给 3 位小朋友,确保没有任何小朋友得到超过 limit 颗糖果,请你返回满足此条件下的 总方案数 。

示例 1:

输入:n = 5, limit = 2
输出:3
解释:总共有 3 种方法分配 5 颗糖果,且每位小朋友的糖果数不超过 2 :(1, 2, 2) ,(2, 1, 2) 和 (2, 2, 1) 。

示例 2:

输入:n = 3, limit = 3
输出:10
解释:总共有 10 种方法分配 3 颗糖果,且每位小朋友的糖果数不超过 3 :(0, 0, 3) ,(0, 1, 2) ,(0, 2, 1) ,(0, 3, 0) ,(1, 0, 2) ,(1, 1, 1) ,(1, 2, 0) ,(2, 0, 1) ,(2, 1, 0) 和 (3, 0, 0) 。

说明:

  • 1 <= n <= 50
  • 1 <= limit <= 50

思路

简单题数据范围小,直接暴力求解。别看不起暴力解法,真想用其它方法求解并不简单。

这道题要求解n个球装到三个容量为limit的盒子里总共有多少种分配方案。如果容量没有限制很简单直接从n+(3-1)个位置中选2个即可。

不暴力求解的话就要考虑动态规划了。// todo

代码

/**
 * @date 2024-06-01 15:59
 */
public class DistributeCandies2928 {
    public int distributeCandies(int n, int limit) {
        int res = 0;
        // 为第一个小朋友分配有0~limit种可能
        for (int i = 0; i <= limit; i++) {
            // 这时为第二个小朋友可以有n - i种可能,这里不要忘了不能超过limit
            for (int j = 0; j <= Math.min(limit, n - i); j++) {
                // 第三个小朋友,获取剩下的糖果,但不能超过limit
                if(n - i - j <= limit){
                    res++;
                }
            }
        }
        return res;
    }
}

性能

2965.找出缺失和重复的数字

目标

给你一个下标从 0 开始的二维整数矩阵 grid,大小为 n * n ,其中的值在 [1, n2] 范围内。除了 a 出现 两次,b 缺失 之外,每个整数都 恰好出现一次 。

任务是找出重复的数字a 和缺失的数字 b 。

返回一个下标从 0 开始、长度为 2 的整数数组 ans ,其中 ans[0] 等于 a ,ans[1] 等于 b 。

示例 1:

输入:grid = [[1,3],[2,2]]
输出:[2,4]
解释:数字 2 重复,数字 4 缺失,所以答案是 [2,4] 。

示例 2:

输入:grid = [[9,1,7],[8,9,2],[3,4,6]]
输出:[9,5]
解释:数字 9 重复,数字 5 缺失,所以答案是 [9,5] 。

说明:

  • 2 <= n == grid.length == grid[i].length <= 50
  • 1 <= grid[i][j] <= n * n
  • 对于所有满足 1 <= x <= n * n 的 x ,恰好存在一个 x 与矩阵中的任何成员都不相等。
  • 对于所有满足 1 <= x <= n * n 的 x ,恰好存在一个 x 与矩阵中的两个成员相等。
  • 除上述的两个之外,对于所有满足 1 <= x <= n * n 的 x ,都恰好存在一对 i, j 满足 0 <= i, j <= n - 1grid[i][j] == x

思路

记录元素的出现次数,选出其中出现次数为2和0的值即可。

网友还给出了一些位运算与数学公式求解的方法,可以降低空间复杂度,不用对每个元素计次,而是使用异或和与数学公式求解。

异或和求解的关键是如何区分得到的 a ^ b,由于a 与 b 不同,异或的结果至少有一个非0位,可以根据该bit位分组,这样每一组中就只含有a或b。

至于数学公式求解的关键是,通过各项和的差可以得到 b - a,各项平方和的差可以得到 b^2 - a^2,进而求得 b + a,解方程组可得a、b。

代码

/**
 * @date 2024-05-31 0:12
 */
public class FindMissingAndRepeatedValues2965 {

/**
     * 公式求和 1,2,……,n^2 以及 1^2,2^2,……,n^2
     * 然后遍历求和,二者之差为b - a 和 b^2 - a^2
     * 进而可以求得b + a,解方程可得a、b
     */
    public int[] findMissingAndRepeatedValues_v2(int[][] grid) {
        int n = grid.length;
        int n2 = n * n;
        long sum = 0;
        long sum2 = 0;
        for (int[] row : grid) {
            for (int i : row) {
                sum += i;
                sum2 += i * i;
            }
        }
        long bsuba = n2 * (n2 + 1L) / 2 - sum;
        long b2suba2 = n2 * (n2 + 1L) * (2 * n2 + 1) / 6 - sum2;
        long badda = b2suba2 / bsuba;
        long b = (badda + bsuba) / 2L;
        long a = badda - b;
        return new int[]{(int) a, (int) b};
    }

    /**
     * 异或和
     */
    public int[] findMissingAndRepeatedValues_v1(int[][] grid) {
        int n = grid.length;
        int n2 = n * n;
        int prefix = 0;
        for (int i = 1; i <= n2; i++) {
            prefix ^= i;
        }
        int tmp = 0;
        for (int[] row : grid) {
            for (int element : row) {
                tmp ^= element;
            }
        }
        int axorb = prefix ^ tmp;
        int shift = Integer.numberOfTrailingZeros(axorb);
        int[] res = new int[2];
        // 由于axorb至少有1bit是不同的,那么根据该bit分组,这样每一组里面a b是分开的
        for (int i = 1; i <= n2; i++) {
            res[i >> shift & 1] ^= i;
        }
        for (int[] row : grid) {
            for (int element : row) {
                res[element >> shift & 1] ^= element;
            }
        }
        // 由于顺序是不确定的,判断出现的为a
        for (int[] row : grid) {
            for (int element : row) {
                if (element == res[0]){
                    return res;
                }
            }
        }
        // 调换位置
        return new int[]{res[1], res[0]};
    }

    public int[] findMissingAndRepeatedValues(int[][] grid) {
        int m = grid.length;
        int n = grid[0].length;
        int l = m * n + 1;
        int[] occurrence = new int[l];
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                occurrence[grid[i][j]]++;
            }
        }
        int[] res = new int[2];
        for (int i = 1; i < l; i++) {
            if (occurrence[i] == 0) {
                res[1] = i;
            } else if (occurrence[i] == 2) {
                res[0] = i;
            }
        }
        return res;
    }
}

性能

2951.找出峰值

目标

给你一个下标从 0 开始的数组 mountain 。你的任务是找出数组 mountain 中的所有 峰值。

以数组形式返回给定数组中 峰值 的下标,顺序不限 。

注意:

  • 峰值 是指一个严格大于其相邻元素的元素。
  • 数组的第一个和最后一个元素 不 是峰值。

示例 1:

输入:mountain = [2,4,4]
输出:[]
解释:mountain[0] 和 mountain[2] 不可能是峰值,因为它们是数组的第一个和最后一个元素。
mountain[1] 也不可能是峰值,因为它不严格大于 mountain[2] 。
因此,答案为 [] 。

示例 2:

输入:mountain = [1,4,3,8,5]
输出:[1,3]
解释:mountain[0] 和 mountain[4] 不可能是峰值,因为它们是数组的第一个和最后一个元素。
mountain[2] 也不可能是峰值,因为它不严格大于 mountain[3] 和 mountain[1] 。
但是 mountain[1] 和 mountain[3] 严格大于它们的相邻元素。
因此,答案是 [1,3] 。

说明:

  • 3 <= mountain.length <= 100
  • 1 <= mountain[i] <= 100

思路

找到大于左右两边元素值的下标。

代码

/**
 * @date 2024-05-28 8:39
 */
public class FindPeaks2951 {
    public List<Integer> findPeaks(int[] mountain) {
        List<Integer> res = new ArrayList<>();
        int n = mountain.length;
        int l = 0;
        int r = 2;
        while (r < n) {
            int i = l + 1;
            if (mountain[i] > mountain[l] && mountain[i] > mountain[r]) {
                res.add(i);
                l = r;
                r += 2;
            } else {
                l++;
                r++;
            }
        }
        return res;
    }
}

性能

2903.找出满足差值条件的下标I

目标

给你一个下标从 0 开始、长度为 n 的整数数组 nums ,以及整数 indexDifference 和整数 valueDifference 。

你的任务是从范围 [0, n - 1] 内找出 2 个满足下述所有条件的下标 i 和 j :

  • abs(i - j) >= indexDifference 且
  • abs(nums[i] - nums[j]) >= valueDifference

返回整数数组 answer。如果存在满足题目要求的两个下标,则 answer = [i, j] ;否则,answer = [-1, -1] 。如果存在多组可供选择的下标对,只需要返回其中任意一组即可。

注意:i 和 j 可能 相等 。

示例 1:

输入:nums = [5,1,4,1], indexDifference = 2, valueDifference = 4
输出:[0,3]
解释:在示例中,可以选择 i = 0 和 j = 3 。
abs(0 - 3) >= 2 且 abs(nums[0] - nums[3]) >= 4 。
因此,[0,3] 是一个符合题目要求的答案。
[3,0] 也是符合题目要求的答案。

示例 2:

输入:nums = [2,1], indexDifference = 0, valueDifference = 0
输出:[0,0]
解释:
在示例中,可以选择 i = 0 和 j = 0 。 
abs(0 - 0) >= 0 且 abs(nums[0] - nums[0]) >= 0 。 
因此,[0,0] 是一个符合题目要求的答案。 
[0,1]、[1,0] 和 [1,1] 也是符合题目要求的答案。 

示例 3:

输入:nums = [1,2,3], indexDifference = 2, valueDifference = 4
输出:[-1,-1]
解释:在示例中,可以证明无法找出 2 个满足所有条件的下标。
因此,返回 [-1,-1] 。

说明:

  • 1 <= n == nums.length <= 100
  • 0 <= nums[i] <= 50
  • 0 <= indexDifference <= 100
  • 0 <= valueDifference <= 50

思路

给我们一个数组,找出其中下标之差大于等于indexDifference,并且值值差大于等于valueDifference的下标,如果不存在返回[-1, -1]。

按照题意我们循环 [0, length),将 [i + indexDifference, length) 的元素分别与 i 进行比较。

题目给定的数据范围比较小,可以使用暴力解法。数据范围变大后这个方法可能会超时,参考 2905.找出满足差值条件的下标 II。

题解给出了一次遍历的题解,只需记录前面的最大与最小值。// todo

代码

/**
 * @date 2024-05-25 20:14
 */
public class FindIndices2903 {
    public int[] findIndices(int[] nums, int indexDifference, int valueDifference) {
        int n = nums.length;
        for (int i = 0; i < n; i++) {
            int r = i + indexDifference;
            while (r < n && Math.abs(nums[i] - nums[r]) < valueDifference) {
                r++;
            }
            if (r < n) {
                return new int[]{i, r};
            }
        }
        return new int[]{-1, -1};
    }
}

性能

2769.找出最大的可达成数字

目标

给你两个整数 num 和 t 。

如果整数 x 可以在执行下述操作不超过 t 次的情况下变为与 num 相等,则称其为 可达成数字 :

  • 每次操作将 x 的值增加或减少 1 ,同时可以选择将 num 的值增加或减少 1 。

返回所有可达成数字中的最大值。可以证明至少存在一个可达成数字。

示例 1:

输入:num = 4, t = 1
输出:6
解释:最大可达成数字是 x = 6 ,执行下述操作可以使其等于 num :
- x 减少 1 ,同时 num 增加 1 。此时,x = 5 且 num = 5 。 
可以证明不存在大于 6 的可达成数字。

示例 2:

输入:num = 3, t = 2
输出:7
解释:最大的可达成数字是 x = 7 ,执行下述操作可以使其等于 num :
- x 减少 1 ,同时 num 增加 1 。此时,x = 6 且 num = 4 。 
- x 减少 1 ,同时 num 增加 1 。此时,x = 5 且 num = 5 。 
可以证明不存在大于 7 的可达成数字。

说明:

  • 1 <= num, t <= 50

思路

给定一个正整数 num,以及操作次数 t,求一个数字 x 能够在 t 次操作后与 num 相等。每一次操作可以使 x 增大或减小1,同时可以选择使 num 增大或减少1。问 x 最大是多少。

要使 x 最大则应该选大于 num 的数,操作减1,为了使 x 尽可能大,应该同时增大 num,使 xnum 相向变化。很明显,x 最大为 num + 2 * t

代码

/**
 * @date 2024-05-21 8:47
 */
public class TheMaximumAchievableX2769 {
    public int theMaximumAchievableX(int num, int t) {
        return num + 2 * t;
    }
}

性能