1182. 与目标颜色间的最短距离

1182. 与目标颜色间的最短距离

给你一个数组 colors,里面有 123 三种颜色。

我们需要在 colors 上进行一些查询操作 queries,其中每个待查项都由两个整数 ic 组成。

现在请你帮忙设计一个算法,查找从索引 i 到具有目标颜色 c 的元素之间的最短距离。

如果不存在解决方案,请返回 -1

示例 1:

输入:colors = [1,1,2,1,3,2,2,3,3], queries = [[1,3],[2,2],[6,1]]
输出:[3,0,3]
解释: 
距离索引 1 最近的颜色 3 位于索引 4(距离为 3)。
距离索引 2 最近的颜色 2 就是它自己(距离为 0)。
距离索引 6 最近的颜色 1 位于索引 3(距离为 3)。

示例 2:

输入:colors = [1,2], queries = [[0,3]]
输出:[-1]
解释:colors 中没有颜色 3。

解法:DP

思想

问题拆分

目标颜色可能在左边也可能在右边,所以拆分成两个子问题

  • 左边与目标颜色的最短距离
  • 右边与目标颜色的最短距离

最后询问时,取 m i n { 左 边 与 目 标 颜 色 的 最 短 距 离 , 右 边 与 目 标 颜 色 的 最 短 距 离 } min \{左边与目标颜色的最短距离, 右边与目标颜色的最短距离\} min{,} 即可

状态表示

  • f ( i , j ) f(i, j) f(i,j) 表示从 colors[0] 开始到 colors[i] 结尾时与 j j j 号颜色的最短距离(左边与目标颜色最短距离)
  • g ( i , j ) g(i, j) g(i,j) 表示从 colors[n - 1] 开始到 colors[i] 结尾时与 j j j 号颜色的最短距离(右边与目标颜色最短距离)

状态转移

  • colors[0] 开始到 colors[i] 结尾时与 j j j 号颜色的最短距离,与从 colors[0] 开始到 colors[i - 1] 结尾时与 j j j 号颜色的最短距离有关,即 f ( i , j ) f(i,j) f(i,j) f ( i − 1 , j ) f(i - 1, j) f(i1,j) 转移
  • colors[n - 1] 开始到 colors[i] 结尾时与 j j j 号颜色的最短距离,与与从 colors[n - 1] 开始到 colors[i + 1] 结尾时与 j j j 号颜色的最短距离有关,即 g ( i , j ) g(i,j) g(i,j) g ( i + 1 , j ) g(i+1,j) g(i+1,j) 转移

复杂度

时间复杂度: O ( m a x { N , M } ) O(max \{N,M \}) O(max{N,M}) N N Ncolors 长度, M M Mqueries 长度

空间复杂度: O ( N ) O(N) O(N)

代码

class Solution {
    public List<Integer> shortestDistanceColor(int[] colors, int[][] queries) {
        int n = colors.length;
        int[][] f = new int[n + 1][4];
        int[][] g = new int[n + 1][4];
        
        for (int i = 0; i <= n; i++) {
            for (int j = 0; j <= 3; j++) {
                f[i][j] = -1;
                g[i][j] = -1;
            }
        }
        
        for (int i = 1; i <= n; i++) {
            for (int j = 1; j <= 3; j++) {
                if (colors[i - 1] == j) {
                    f[i][j] = 0;
                } else {
                    if (f[i - 1][j] == -1) f[i][j] = -1;
                    else f[i][j] = f[i - 1][j] + 1;
                }
            }
        }
        
        for (int i = n - 1; i >= 0; i--) {
            for (int j = 1; j <= 3; j++) {
                if (colors[i] == j) {
                    g[i][j] = 0;
                } else {
                    if (g[i + 1][j] == -1) g[i][j] = -1;
                    else g[i][j] = g[i + 1][j] + 1;
                }
            }
        }

        List<Integer> res = new ArrayList<>();
        for (var q : queries) {
            int a = f[q[0] + 1][q[1]], b = g[q[0]][q[1]];
            if (a == -1 && b == -1) res.add(-1);
            else if (a == -1) res.add(b);
            else if (b == -1) res.add(a);
            else res.add(Math.min(a, b));
        }
        
        return res;
    }

}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
这是一个优化问题,可以使用模拟退火算法来解决。以下是一个简单的实现过程: 1. 随机生成初始解:将三个医疗点随机放置在村庄中。 2. 计算初始解的目标函数值:计算所有村庄到最近的医疗点的距离总和S1。 3. 迭代优化过程:在每次迭代中,随机选择一个医疗点,将其移动到一个新的位置,计算新解的目标函数值S1'。如果S1' < S1,接受新解;否则以一定概率接受新解。重复该过程直到满足停止条件。 4. 输出最优解:迭代完成后,输出S1最小的三个医疗点的位置以及总距离S1的值。 5. 计算维修道路的总里程S2:对于每个村庄,计算其到所属医疗点的路径,并累加路径长度得到S2。 6. 用不同颜色标记各村庄到医疗点使用的道路:可以使用MATLAB中的plot函数来绘制路径。 以下是MATLAB代码示例: ```matlab % 生成随机村庄位置 num_villages = 20; village_pos = rand(num_villages, 2); % 初始解:随机放置三个医疗点 num_medical_centers = 3; medical_center_pos = rand(num_medical_centers, 2); % 迭代优化过程 max_iter = 1000; T = 1.0; % 初始温度 T_min = 0.01; % 最小温度 alpha = 0.99; % 降温速率 S1 = calc_distance(village_pos, medical_center_pos); % 初始距离总和 while T > T_min for i = 1:max_iter % 随机选择一个医疗点 center_idx = randi(num_medical_centers); % 生成新位置 new_pos = medical_center_pos(center_idx, :) + randn(1, 2); % 计算新解的距离总和 new_medical_center_pos = medical_center_pos; new_medical_center_pos(center_idx, :) = new_pos; S1_new = calc_distance(village_pos, new_medical_center_pos); % 判断是否接受新解 if S1_new < S1 S1 = S1_new; medical_center_pos = new_medical_center_pos; elseif exp((S1 - S1_new) / T) > rand() medical_center_pos = new_medical_center_pos; end end T = T * alpha; end % 输出最优解 disp('最小距离总和:') disp(S1) disp('医疗点位置:') disp(medical_center_pos) % 计算维修道路的总里程 S2 = 0; for i = 1:num_villages [~, nearest_medical_center] = min(calc_distance(village_pos(i, :), medical_center_pos)); S2 = S2 + norm(village_pos(i, :) - medical_center_pos(nearest_medical_center, :)); end disp('维修道路的总里程:') disp(S2) % 用不同颜色标记各村庄到医疗点使用的道路 colors = {'r', 'g', 'b'}; figure hold on for i = 1:num_villages [~, nearest_medical_center] = min(calc_distance(village_pos(i, :), medical_center_pos)); plot([village_pos(i, 1), medical_center_pos(nearest_medical_center, 1)], ... [village_pos(i, 2), medical_center_pos(nearest_medical_center, 2)], ... colors{nearest_medical_center}) end scatter(medical_center_pos(:, 1), medical_center_pos(:, 2), 'k', 'filled') scatter(village_pos(:, 1), village_pos(:, 2), 'k') hold off function D = calc_distance(A, B) % 计算两个矩阵中所有点之的距离 D = sqrt(sum((permute(A, [1, 3, 2]) - permute(B, [3, 1, 2])).^2, 3)); end ``` 注意:该代码只是一个简单的实现示例,可能存在优化空。例如,可以考虑不同的温度降低策略,或者使用更复杂的目标函数。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值