2833.距离原点最远的点

目标

给你一个长度为 n 的字符串 moves ,该字符串仅由字符 'L'、'R' 和 '_' 组成。字符串表示你在一条原点为 0 的数轴上的若干次移动。

你的初始位置就在原点(0),第 i 次移动过程中,你可以根据对应字符选择移动方向:

  • 如果 moves[i] = 'L' 或 moves[i] = '_' ,可以选择向左移动一个单位距离
  • 如果 moves[i] = 'R' 或 moves[i] = '_' ,可以选择向右移动一个单位距离

移动 n 次之后,请你找出可以到达的距离原点 最远 的点,并返回 从原点到这一点的距离 。

示例 1:

输入:moves = "L_RL__R"
输出:3
解释:可以到达的距离原点 0 最远的点是 -3 ,移动的序列为 "LLRLLLR" 。

示例 2:

输入:moves = "_R__LL_"
输出:5
解释:可以到达的距离原点 0 最远的点是 -5 ,移动的序列为 "LRLLLLL" 。

示例 3:

输入:moves = "_______"
输出:7
解释:可以到达的距离原点 0 最远的点是 7 ,移动的序列为 "RRRRRRR" 。

说明:

  • 1 <= moves.length == n <= 50
  • moves 仅由字符 'L'、'R' 和 '_' 组成

思路

开始时站在在数轴原点,根据数组 moves 移动,L -1 R +1 _ 可以任选方向,求所能到达的距离原点最远的距离。

LR 是固定的,要使距离最远 _ 应该都朝一个方向移动,可以先判断 LR 移动后位于原点的左侧还是右侧,然后 _ 的移动方向与之保持一致即可。

代码


/**
 * @date 2026-04-24 8:50
 */
public class FurthestDistanceFromOrigin2833 {

    public int furthestDistanceFromOrigin(String moves) {
        int n = moves.length();
        int d = 0;
        int c = 0;
        for (int i = 0; i < n; i++) {
            if (moves.charAt(i) == 'L') {
                d--;
            } else if (moves.charAt(i) == 'R') {
                d++;
            } else {
                c++;
            }
        }
        return d > 0 ? d + c : -d + c;
    }
}

性能

2078.两栋颜色不同且距离最远的房子

目标

街上有 n 栋房子整齐地排成一列,每栋房子都粉刷上了漂亮的颜色。给你一个下标从 0 开始且长度为 n 的整数数组 colors ,其中 colors[i] 表示第 i 栋房子的颜色。

返回 两栋 颜色 不同 房子之间的 最大 距离。

第 i 栋房子和第 j 栋房子之间的距离是 abs(i - j) ,其中 abs(x) 是 x 的绝对值。

示例 1:

输入:colors = [1,1,1,6,1,1,1]
输出:3
解释:上图中,颜色 1 标识成蓝色,颜色 6 标识成红色。
两栋颜色不同且距离最远的房子是房子 0 和房子 3 。
房子 0 的颜色是颜色 1 ,房子 3 的颜色是颜色 6 。两栋房子之间的距离是 abs(0 - 3) = 3 。
注意,房子 3 和房子 6 也可以产生最佳答案。

示例 2:

输入:colors = [1,8,3,8,3]
输出:4
解释:上图中,颜色 1 标识成蓝色,颜色 8 标识成黄色,颜色 3 标识成绿色。
两栋颜色不同且距离最远的房子是房子 0 和房子 4 。
房子 0 的颜色是颜色 1 ,房子 4 的颜色是颜色 3 。两栋房子之间的距离是 abs(0 - 4) = 4 。

示例 3:

输入:colors = [0,1]
输出:1
解释:两栋颜色不同且距离最远的房子是房子 0 和房子 1 。
房子 0 的颜色是颜色 0 ,房子 1 的颜色是颜色 1 。两栋房子之间的距离是 abs(0 - 1) = 1 。

说明:

  • n == colors.length
  • 2 <= n <= 100
  • 0 <= colors[i] <= 100
  • 生成的测试数据满足 至少 存在 2 栋颜色不同的房子

思路

有一排房子,colors[i] 表示房子 i 的颜色,求不同颜色的房子之间的最远距离。

暴力解法是写一个双重循环,内层从后往前遍历,直到找到第一个不同的颜色下标。

O(n) 的解法是找到不等于首尾颜色的最小与最大下标,想清楚首尾房子一定参与最远距离的计算。如果 colors[0] != colors[n - 1] 直接返回 n - 1,否则,假设首尾的颜色均为 c,找到颜色不为 c 的下标最大值 r 与最小值 l,取 max(r, n - 1 - l)

可以使用反证法证明,假设最远距离 i, j 在中间 0 < i < j < n - 1colors[i] = a, colors[j] = b, colors[0] == colors[n - 1] == c

  • 如果 a != c && b != c,显然 (0, j) 或者 (i, n - 1) 距离更远
  • 如果 a == c && b != c,那么 (0, j) 距离更远
  • 如果 a != c && b == c,那么 (i, n - 1) 更远

代码


/**
 * @date 2026-04-20 8:55
 */
public class MaxDistance2078 {

    public int maxDistance(int[] colors) {
        int n = colors.length;
        int res = 0;
        for (int i = 0; i < n; i++) {
            for (int j = n - 1; j > i; j--) {
                if (colors[i] != colors[j]) {
                    res = Math.max(res, j - i);
                    break;
                }
            }
        }
        return res;
    }
}

性能

3783.整数的镜像距离

目标

给你一个整数 n。

定义它的 镜像距离 为:abs(n - reverse(n)),其中 reverse(n) 表示将 n 的数字反转后形成的整数。

返回表示 n 的镜像距离的整数。

其中,abs(x) 表示 x 的绝对值。

示例 1:

输入: n = 25
输出: 27
解释:
reverse(25) = 52。
因此,答案为 abs(25 - 52) = 27。

示例 2:

输入: n = 10
输出: 9
解释:
reverse(10) = 01,即 1。
因此,答案为 abs(10 - 1) = 9。

示例 3:

输入: n = 7
输出: 0
解释:
reverse(7) = 7。
因此,答案为 abs(7 - 7) = 0。

说明:

  • 1 <= n <= 10^9

思路

反转整数 n 的十进制表示,计算 abs(n - reverse(n))

代码


/**
 * @date 2026-04-18 0:30
 */
public class MirrorDistance3783 {

    public int mirrorDistance(int n) {
        int r = 0;
        int base = 10;
        int t = n;
        while (t > 0) {
            r = r * base + t % 10;
            t /= 10;
        }
        return Math.abs(r - n);
    }
}

性能

2515.到目标字符串的最短距离

目标

给你一个下标从 0 开始的 环形 字符串数组 words 和一个字符串 target 。环形数组 意味着数组首尾相连。

  • 形式上, words[i] 的下一个元素是 words[(i + 1) % n] ,而 words[i] 的前一个元素是 words[(i - 1 + n) % n] ,其中 n 是 words 的长度。

从 startIndex 开始,你一次可以用 1 步移动到下一个或者前一个单词。

返回到达目标字符串 target 所需的最短距离。如果 words 中不存在字符串 target ,返回 -1 。

示例 1:

输入:words = ["hello","i","am","leetcode","hello"], target = "hello", startIndex = 1
输出:1
解释:从下标 1 开始,可以经由以下步骤到达 "hello" :
- 向右移动 3 个单位,到达下标 4 。
- 向左移动 2 个单位,到达下标 4 。
- 向右移动 4 个单位,到达下标 0 。
- 向左移动 1 个单位,到达下标 0 。
到达 "hello" 的最短距离是 1 。

示例 2:

输入:words = ["a","b","leetcode"], target = "leetcode", startIndex = 0
输出:1
解释:从下标 0 开始,可以经由以下步骤到达 "leetcode" :
- 向右移动 2 个单位,到达下标 2 。
- 向左移动 1 个单位,到达下标 2 。
到达 "leetcode" 的最短距离是 1 。

示例 3:

输入:words = ["i","eat","leetcode"], target = "ate", startIndex = 0
输出:-1
解释:因为 words 中不存在字符串 "ate" ,所以返回 -1 。

说明:

  • 1 <= words.length <= 100
  • 1 <= words[i].length <= 100
  • words[i] 和 target 仅由小写英文字母组成
  • 0 <= startIndex < words.length

思路

循环字符串数组 words,从 startIndex 开始,向左或向右查找 target,返回 targetstartIndex 最短的距离,如果不存在返回 -1

从前向后遍历,如果找到 target,记录循环数组中的距离,d 或者 n - d,返回所有距离中的最小值。

或值从 startIndex 开始遍历距离,如果找到 target 则直接返回,需要处理循环数组的下标,(startIndex + i) % n(startIndex - i + n) % n

代码


/**
 * @date 2026-04-15 8:47
 */
public class ClosestTarget2515 {

    public int closestTarget(String[] words, String target, int startIndex) {
        int n = words.length;
        for (int i = 0; i < n; i++) {
            if (words[(startIndex + i) % n].equals(target) || words[(startIndex - i + n) % n].equals(target)) {
                return i;
            }
        }
        return -1;
    }
}

性能

1848.到目标元素的最小距离

目标

给你一个整数数组 nums (下标 从 0 开始 计数)以及两个整数 target 和 start ,请你找出一个下标 i ,满足 nums[i] == target 且 abs(i - start) 最小化 。注意:abs(x) 表示 x 的绝对值。

返回 abs(i - start) 。

题目数据保证 target 存在于 nums 中。

示例 1:

输入:nums = [1,2,3,4,5], target = 5, start = 3
输出:1
解释:nums[4] = 5 是唯一一个等于 target 的值,所以答案是 abs(4 - 3) = 1 。

示例 2:

输入:nums = [1], target = 1, start = 0
输出:0
解释:nums[0] = 1 是唯一一个等于 target 的值,所以答案是 abs(0 - 0) = 0 。

示例 3:

输入:nums = [1,1,1,1,1,1,1,1,1,1], target = 1, start = 0
输出:0
解释:nums 中的每个值都是 1 ,但 nums[0] 使 abs(i - start) 的结果得以最小化,所以答案是 abs(0 - 0) = 0 。

说明:

  • 1 <= nums.length <= 1000
  • 1 <= nums[i] <= 10^4
  • 0 <= start < nums.length
  • target 存在于 nums 中

思路

返回元素值为 target 的下标与 start 的最短距离。

可以从 0 开始遍历,也可以枚举距离从 start 向两边遍历。

代码


/**
 * @date 2026-04-13 8:52
 */
public class GetMinDistance1848 {

    public int getMinDistance(int[] nums, int target, int start) {
        int n = nums.length;
        int res = Integer.MAX_VALUE;
        for (int i = 0; i < n; i++) {
            if (nums[i] == target) {
                res = Math.min(res, Math.abs(i - start));
            }
        }
        return res;
    }
}

性能

3740.三个相等元素之间的最小距离I

目标

给你一个整数数组 nums。

如果满足 nums[i] == nums[j] == nums[k],且 (i, j, k) 是 3 个 不同 下标,那么三元组 (i, j, k) 被称为 有效三元组 。

有效三元组 的 距离 被定义为 abs(i - j) + abs(j - k) + abs(k - i),其中 abs(x) 表示 x 的 绝对值 。

返回一个整数,表示 有效三元组 的 最小 可能距离。如果不存在 有效三元组 ,返回 -1。

示例 1:

输入: nums = [1,2,1,1,3]
输出: 6
解释:
最小距离对应的有效三元组是 (0, 2, 3) 。
(0, 2, 3) 是一个有效三元组,因为 nums[0] == nums[2] == nums[3] == 1。它的距离为 abs(0 - 2) + abs(2 - 3) + abs(3 - 0) = 2 + 1 + 3 = 6。

示例 2:

输入: nums = [1,1,2,3,2,1,2]
输出: 8
解释:
最小距离对应的有效三元组是 (2, 4, 6) 。
(2, 4, 6) 是一个有效三元组,因为 nums[2] == nums[4] == nums[6] == 2。它的距离为 abs(2 - 4) + abs(4 - 6) + abs(6 - 2) = 2 + 2 + 4 = 8。

示例 3:

输入: nums = [1]
输出: -1
解释:
不存在有效三元组,因此答案为 -1。

说明:

  • 1 <= n == nums.length <= 100
  • 1 <= nums[i] <= n

思路

有一个数组 nums,定义有效三元组是数组中三个相同元素的下标,有效三元组的距离定义为三元组两两元素间的距离之和,求有效三元组的最小距离,如果没有有效三元组,返回 -1

使用哈希表记录相同元素的下标,以中间下标为基准,要使距离最小,显然只需考虑相邻的下标即可。

三元组 a b c 的距离是 c - a + c - b + b - a = 2 * c - 2 * a

暴力解法是 O(n^3),先找到相等的 a b,再找相等的 b c。

代码


/**
 * @date 2026-04-10 8:46
 */
public class MinimumDistance3740 {

    public int minimumDistance(int[] nums) {
        Map<Integer, List<Integer>> map = new HashMap<>();
        int n = nums.length;
        for (int i = 0; i < n; i++) {
            map.putIfAbsent(nums[i], new ArrayList<>());
            map.get(nums[i]).add(i);
        }
        int res = Integer.MAX_VALUE;
        for (List<Integer> list : map.values()) {
            int size = list.size();
            if (size < 3) {
                continue;
            }
            for (int i = 2; i < size; i++) {
                res = Math.min(res, list.get(i) * 2 - list.get(i - 2) * 2);
            }
        }
        return res == Integer.MAX_VALUE ? -1 : res;
    }
}

性能

657.机器人能否返回原点

目标

在二维平面上,有一个机器人从原点 (0, 0) 开始。给出它的移动顺序,判断这个机器人在完成移动后是否在 (0, 0) 处结束。

移动顺序由字符串 moves 表示。字符 move[i] 表示其第 i 次移动。机器人的有效动作有 R(右),L(左),U(上)和 D(下)。

如果机器人在完成所有动作后返回原点,则返回 true。否则,返回 false。

注意:机器人“面朝”的方向无关紧要。 “R” 将始终使机器人向右移动一次,“L” 将始终向左移动等。此外,假设每次移动机器人的移动幅度相同。

示例 1:

输入: moves = "UD"
输出: true
解释:机器人向上移动一次,然后向下移动一次。所有动作都具有相同的幅度,因此它最终回到它开始的原点。因此,我们返回 true。

示例 2:

输入: moves = "LL"
输出: false
解释:机器人向左移动两次。它最终位于原点的左侧,距原点有两次 “移动” 的距离。我们返回 false,因为它在移动结束时没有返回原点。

说明:

  • 1 <= moves.length <= 2 * 10^4
  • moves 只包含字符 'U', 'D', 'L' 和 'R'

思路

二维平面的原点 (0, 0) 上有一个机器人,字符串 moves 表示机器人的移动顺序,机器人可以上下左右移动,判断移动后机器人是否仍在原点。

依题意模拟判断即可。

代码


/**
 * @date 2026-04-07 11:10
 */
public class JudgeCircle657 {

    public boolean judgeCircle(String moves) {
        char[] chars = moves.toCharArray();
        int x = 0, y = 0;
        for (char c : chars) {
            if (c == 'L') {
                x--;
            } else if (c == 'R') {
                x++;
            } else if (c == 'U') {
                y++;
            } else {
                y--;
            }
        }
        return x == 0 && y == 0;
    }
}

性能

2839.判断通过操作能否让字符串相等I

目标

给你两个字符串 s1 和 s2 ,两个字符串的长度都为 4 ,且只包含 小写 英文字母。

你可以对两个字符串中的 任意一个 执行以下操作 任意 次:

  • 选择两个下标 i 和 j 且满足 j - i = 2 ,然后 交换 这个字符串中两个下标对应的字符。

如果你可以让字符串 s1 和 s2 相等,那么返回 true ,否则返回 false 。

示例 1:

输入:s1 = "abcd", s2 = "cdab"
输出:true
解释: 我们可以对 s1 执行以下操作:
- 选择下标 i = 0 ,j = 2 ,得到字符串 s1 = "cbad" 。
- 选择下标 i = 1 ,j = 3 ,得到字符串 s1 = "cdab" = s2 。

示例 2:

输入:s1 = "abcd", s2 = "dacb"
输出:false
解释:无法让两个字符串相等。

说明:

  • s1.length == s2.length == 4
  • s1 和 s2 只包含小写英文字母。

思路

有两个长度为 4 的字符串 s1 和 s2,判断能否通过操作使二者相等,每次操作可将第一个与第三个 或者 第二个与第四个 字母交换。

实际上就是判断 s1[0]s1[2] 与 s2[0]s2[2] 或者 s2[2]s2[0] ,以及 s1[1]s1[3] 与 s2[1]s2[3] 或者 s2[3]s2[1] 是否相等。

为了避免复杂判断,直接根据奇偶性分组,s1 中的字母 +1s2 中的字母 -1,最后判断字母出现次数是否为 0 即可。

代码


/**
 * @date 2026-03-29 16:28
 */
public class CanBeEqual2839 {

    public boolean canBeEqual(String s1, String s2) {
        char[] chars1 = s1.toCharArray();
        char[] chars2 = s2.toCharArray();
        Map<Character, Integer>[] map = new HashMap[2];
        Arrays.setAll(map, x -> new HashMap<>());
        for (int i = 0; i < 4; i++) {
            int rem = i % 2;
            map[rem].merge(chars1[i], 1, Integer::sum);
            map[rem].merge(chars2[i], -1, Integer::sum);
        }
        for (int i = 0; i < 2; i++) {
            for (Integer value : map[i].values()) {
                if (value != 0) {
                    return false;
                }
            }
        }
        return true;
    }

}

性能

2946.循环移位后的矩阵相似检查

目标

给你一个下标从 0 开始且大小为 m x n 的整数矩阵 mat 和一个整数 k 。请你将矩阵中的 奇数 行循环 右 移 k 次,偶数 行循环 左 移 k 次。

如果初始矩阵和最终矩阵完全相同,则返回 true ,否则返回 false 。

示例 1:

输入:mat = [[1,2,1,2],[5,5,5,5],[6,3,6,3]], k = 2
输出:true
解释:
初始矩阵如图一所示。
图二表示对奇数行右移一次且对偶数行左移一次后的矩阵状态。
图三是经过两次循环移位后的最终矩阵状态,与初始矩阵相同。
因此,返回 true 。

示例 2:

输入:mat = [[2,2],[2,2]], k = 3
输出:true
解释:由于矩阵中的所有值都相等,即使进行循环移位,矩阵仍然保持不变。因此,返回 true 。

示例 3:

输入:mat = [[1,2]], k = 1
输出:false
解释:循环移位一次后,mat = [[2,1]],与初始矩阵不相等。因此,返回 false 。

说明:

  • 1 <= mat.length <= 25
  • 1 <= mat[i].length <= 25
  • 1 <= mat[i][j] <= 25
  • 1 <= k <= 50

思路

有一个 m x n 矩阵 mat,将奇数行(行标 1 开始)右移 k,偶数行左移 k,判断最终矩阵与初始矩阵是否相同。

依题意模拟即可,右移后的下标 (i + k) % n,左移后的下标 (i - k + n) % n

实际上无需判断奇偶行,row[i] 左移 k 之后是否等于 row[i],等价于 row[i] 右移 k 之后是否等于 row[i]

代码


/**
 * @date 2026-03-27 8:56
 */
public class AreSimilar2946 {

    public boolean areSimilar(int[][] mat, int k) {
        int n = mat[0].length;
        for (int[] row : mat) {
            for (int j = 0; j < n; j++) {
                if (row[j] != row[(j + k) % n]) {
                    return false;
                }
            }
        }
        return true;
    }

}

性能

1886.判断矩阵经轮转后是否一致

目标

给你两个大小为 n x n 的二进制矩阵 mat 和 target 。现 以 90 度顺时针轮转 矩阵 mat 中的元素 若干次 ,如果能够使 mat 与 target 一致,返回 true ;否则,返回 false 。

示例 1:

输入:mat = [[0,1],[1,0]], target = [[1,0],[0,1]]
输出:true
解释:顺时针轮转 90 度一次可以使 mat 和 target 一致。

示例 2:

输入:mat = [[0,1],[1,1]], target = [[1,0],[0,1]]
输出:false
解释:无法通过轮转矩阵中的元素使 equal 与 target 一致。

示例 3:

输入:mat = [[0,0,0],[0,1,0],[1,1,1]], target = [[1,1,1],[0,1,0],[0,0,0]]
输出:true
解释:顺时针轮转 90 度两次可以使 mat 和 target 一致。

说明:

  • n == mat.length == target.length
  • n == mat[i].length == target[i].length
  • 1 <= n <= 10
  • mat[i][j] 和 target[i][j] 不是 0 就是 1

思路

两个 n x n 矩阵 mattarget,判断能否通过若干次顺时针旋转 90° 使得 mattarget 相等。

参考 48.旋转图像 直接原地旋转 mat 比较两个矩阵是否相等,最多旋转 4 次。

代码


/**
 * @date 2026-04-16 17:10
 */
public class FindRotation1886 {

    public boolean findRotation(int[][] mat, int[][] target) {
        int n = mat.length;
        here:
        for (int i = 0; i < 4; i++) {
            rotate(mat);
            for (int a = 0; a < n; a++) {
                for (int b = 0; b < n; b++) {
                    if (mat[a][b] != target[a][b]) {
                        continue here;
                    }
                }
            }
            return true;
        }
        return false;
    }

    public void rotate(int[][] matrix) {
        int n = matrix.length;
        for (int i = 0; i < n / 2; ++i) {
            for (int j = 0; j < (n + 1) / 2; ++j) {
                int temp = matrix[i][j];
                matrix[i][j] = matrix[n - j - 1][i];
                matrix[n - j - 1][i] = matrix[n - i - 1][n - j - 1];
                matrix[n - i - 1][n - j - 1] = matrix[j][n - i - 1];
                matrix[j][n - i - 1] = temp;
            }
        }
    }

}

性能