Shortest Unsorted Continuous Subarray 最短无序连续子数组

本文介绍了一种算法,用于寻找并返回使整个数组变为升序所需的最短子数组长度。该算法通过四次遍历数组来确定需要排序的子数组边界。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

给定一个整数数组,你需要寻找一个连续的子数组,如果对这个子数组进行升序排序,那么整个数组都会变为升序排序。

你找到的子数组应是最短的,请输出它的长度。

示例 1:

输入: [2, 6, 4, 8, 10, 9, 15]
输出: 5
解释: 你只需要对 [6, 4, 8, 10, 9] 进行升序排序,那么整个表都会变为升序排序。

说明 :

  1. 输入的数组长度范围在 [1, 10,000]。
  2. 输入的数组可能包含重复元素 ,所以升序的意思是<=。

思路:如图所示:

Unsorted_subarray

需要遍历4次数组:

第一次:从左往右,找出下降的最小的值,如b所示。

第二次:从右往左,找出上升的最大的值,如a所示。

第三次:从左往右,找出第一个大于b的下标,如图下标为1

第四次:从右往左,找出第一个小于a的下标,如图下标为6

参考代码:

class Solution {
public:
    int findUnsortedSubarray(vector<int>& nums) {
        if(nums.empty() || nums.size()<=1) return 0;
        int minValue=INT_MAX,maxValue=INT_MIN;
        for(int i=1;i<nums.size();i++){
            if(nums[i]<nums[i-1]) minValue=min(minValue,nums[i]);
        }
        for(int i=nums.size()-2;i>=0;i--){
            if(nums[i]>nums[i+1]) maxValue=max(maxValue,nums[i]);
        }
        int l=-1,r=-2;
        for(int i=0;i<nums.size();i++){
            if(nums[i]>minValue) {
                l=i;
                break;
            }
        }
        for(int i=nums.size()-1;i>=0;i--){
            if(nums[i]<maxValue) {
                r=i;
                break;
            }
        }
        return r>l?r-l+1:0;
    }
};

 

<think>我们有一个明确的任务:使用DFS生成迷宫,使用BFS寻找路径,并用二维数组表示迷宫,后实现可视化。根据引用[2]中提到的,我们可以参考一个完整的迷宫算法实现,包括DFS和BFS,迷宫生成以及可视化。步骤:1.迷宫表示:使用二维数组(矩阵)。通常,0表示通道(可走),1表示墙(不可走)。同时,我们需要起点和终点。2.迷宫生成:使用深度优先搜索(DFS)算法生成随机迷宫。DFS生成迷宫通常使用递归回溯或栈来实现。基本思想是从一个单元格开始,随机选择相邻未访问的单元格,打通墙壁,并递归进行,直到所有单元格都被访问。3.迷宫求解:使用广度优先搜索(BFS)寻找路径。BFS可以保证找到的是路径,因为它按层次遍历。4.可视化:将迷宫和路径用图形方式显示出来。我们可以使用文本字符(如'#'表示墙,空格表示通道,'.'表示路径)或者使用图形库(如pygame,matplotlib等)。这里为了简单,我们可以先用文本方式,然后可以考虑使用图形界面。详细步骤:一、迷宫生成(DFS):-初始化一个网格,所有单元格之间的墙都存在,每个单元格初始状态为未访问。-选择一个起始单元格(例如(0,0)),将其标记为已访问,并加入栈。-当栈非空时:1.从栈中弹出一个单元格作为当前单元格。2.检查当前单元格是否有未访问的相邻单元格(上下左右):如果有,随机选择一个未访问的相邻单元格:-将当前单元格压回栈。-打通当前单元格与相邻单元格之间的墙(将两个单元格之间的墙壁设为通道,并将相邻单元格设为通道)。-将相邻单元格标记为已访问,并将其压入栈。3.如果没有未访问的相邻单元格,则继续弹出栈顶。注意:迷宫通常用奇数大小的网格(因为迷宫通道和墙交替,起点和终点在通道上)。例如,我们设定一个大小为height×width的网格,实际迷宫的大小为(2*height+1) ×(2*width+1),其中0表示墙,1表示通道。但也可以直接使用一个二维数组,每个单元格代表一个房间,然后打通相邻房间的墙。另一种常见方法是:将迷宫数组初始化为全部是墙(1),然后从起点(1,1)开始,将起点设为通道(0),然后递归地打通相邻的墙(注意相邻两个单元格之间的墙也要打通,所以实际上要打通两个位置:当前单元格和相邻单元格之间的墙,以及相邻单元格本身)。二、迷宫求解(BFS):-从起点开始,将起点加入队列,并记录起点到每个点的距离(或记录前驱节点)。-每次从队列中取出一个单元格,检查其四个方向(上下左右)的相邻单元格(必须是通道且未被访问过)。-如果相邻单元格是终点,则回溯路径(通过记录的前驱节点)。-否则,将相邻单元格标记为已访问,加入队列,并记录前驱。三、可视化:-打印迷宫:遍历二维数组,根据数组的值输出不同的字符。-在求解后,将路径上的点(起点和终点除外)在迷宫中用特殊字符(如'.')标记,然后打印。我们将按照以下步骤实现代码(使用Python):1.定义迷宫大小(例如:高度和宽度,注意实际数组大小)2.初始化迷宫数组(全部为墙)3.使用DFS生成迷宫4.设置起点和终点(通常起点为(1,1),终点为(height-2, width-2))5.使用BFS求解路径6.可视化迷宫和路径注意:为了简化,我们使用一个二维数组表示迷宫,其中0表示通道,1表示墙。在生成迷宫时,我们使用一个比实际迷宫房间数大的数组(因为每个房间之间都有墙)。例如:我们想要一个5×5的房间迷宫,那么实际数组大小应该是(2*5+1)× (2*5+1)=11×11。但也可以使用更简单的方式:我们直接使用一个二维数组,每个位置代表一个房间,然后打通相邻房间的墙时,同时打通两个房间之间的墙壁(在数组上表现为两个房间之间的位置设为0)。这里我们采用一种常见的DFS迷宫生成方法,使用递归回溯(栈)来生成。具体实现如下:1.初始化一个全为1(墙)的二维数组,大小为heightx width(这里height和宽度都是奇数)。2.设置起点(1,1)为0(通道)。3.创建一个栈,将起点入栈,并记录起点已访问。4.定义四个方向(上下左右)的偏移量,以及每个方向需要打通的墙的位置(因为相邻两个房间之间有一个墙,这个墙的位置在中间,所以方向偏移量是2?)但是注意:我们的数组每个格子代表一个墙或通道,相邻房间的坐标差为2(行和列都是)。例如:当前房间在(r, c),那么相邻房间在(r+2, c), (r-2,c),(r, c+2), (r,c-2)。而这两个房间之间的墙在(r+1,c),(r-1,c),(r,c+1),(r,c-1)。因此,在打通相邻房间时,需要将相邻房间设为0,同时将中间的墙设为0。代码结构:我们用一个类来实现,或者用函数实现。这里为了清晰,我们用函数实现。步骤:1.创建迷宫数组(全1)2.设置起点(1,1)为0,并标记为已访问。3.栈中放入起点。4.当栈非空:pop当前单元格获取当前单元格的四个随机排列的邻居(上下左右,且距离为2的单元格)对于每个邻居:如果该邻居未被访问过(在数组范围内且值为1):将当前单元格压回栈打通当前单元格和邻居之间的墙(即当前单元格和邻居之间的位置设为0)将邻居设为0,并标记为已访问,压入栈注意:邻居的坐标必须在迷宫范围内(行从1到height-2,列从1到width-2,且步长为2?)实际上,我们只考虑奇数行奇数列作为房间(因为我们的起点(1,1)是奇数索引)。但是,我们也可以使用另一种方法:将迷宫数组的每个位置都视为房间,但这样房间之间没有墙。所以通常采用上述方法(每个房间在奇数行奇数列,墙在偶数行偶数列?)不对,应该是:我们使用一个数组,其中每个房间占据一个格子(行和列都是奇数索引),而墙则是其他格子。因此,房间的坐标是(1,1),(1,3), (1,5)...,(3,1)等。因此,在生成迷宫时,我们只考虑这些房间格子(即行索引和列索引都是奇数的格子)。具体实现中,我们可以这样:height,width为迷宫实际数组的行数和列数(都是奇数)房间的坐标范围:行从1到height-2,步长2;列从1到width-2,步长2。生成迷宫后,我们设置起点和终点。通常起点为(1,1),终点为(height-2,width-2)。然后,我们使用BFS来寻找从起点到终点的路径。 BFS步骤:创建一个队列,将起点入队。创建一个visited数组(与迷宫同大小),记录每个位置是否被访问过,并记录前驱(或者记录到达该位置的步数,以及从哪个位置来)。从队列中取出一个位置,检查其四个方向(上下左右,注意步长为1,因为相邻的通道可能是上下左右相邻的格子,而不是跳两格,因为我们已经打通了墙,所以相邻的通道就是上下左右相邻的格子)。如果遇到终点,则回溯路径。后,我们将路径上的点(除了起点和终点)在迷宫数组中标记为2(或者用另一个字符表示),然后打印迷宫。可视化:我们可以用字符打印,也可以用图形库。这里先用字符打印。现在,我们编写代码:注意:为了随机选择邻居,我们将四个方向随机排序。代码实现如下:</think>以下是一个完整的迷宫生成与求解实现方案,使用深度优先搜索(DFS)生成随机迷宫,广度优先搜索(BFS)寻找路径,并通过二维数组表示迷宫结构: ```python import numpy as np import matplotlib.pyplot as plt from collections import deque import random class MazeGenerator: def __init__(self, width=21, height=21): """初始化迷宫参数""" self.width = width self.height = height # 确保迷宫尺寸为奇数 if self.width % 2 == 0: self.width += 1 if self.height % 2 == 0: self.height += 1 # 初始化迷宫矩阵(1表示墙,0表示通道) self.maze = np.ones((self.height, self.width), dtype=int) # 设置起点和终点 self.start = (1, 1) self.end = (self.height - 2, self.width - 2) def generate_with_dfs(self): """使用DFS算法生成随机迷宫""" # 设置起点为通道 self.maze[self.start] = 0 # DFS使用的栈和访问标记 stack = [self.start] visited = set([self.start]) # 四个方向:上、右、下、左 directions = [(-2, 0), (0, 2), (2, 0), (0, -2)] while stack: current = stack[-1] cy, cx = current # 获取未访问的相邻位置 neighbors = [] for dy, dx in directions: ny, nx = cy + dy, cx + dx if (0 <= ny < self.height and 0 <= nx < self.width and self.maze[ny, nx] == 1 and (ny, nx) not in visited): neighbors.append((ny, nx, (cy + dy//2, cx + dx//2))) if neighbors: # 随机选择下一个位置 next_y, next_x, wall = random.choice(neighbors) # 打通当前到下一个位置的墙 self.maze[next_y, next_x] = 0 self.maze[wall[0], wall[1]] = 0 # 标记为已访问 visited.add((next_y, next_x)) stack.append((next_y, next_x)) else: # 回溯 stack.pop() # 确保终点是通道 self.maze[self.end] = 0 return self.maze def find_path_with_bfs(self): """使用BFS算法寻找路径""" # 方向:上、右、下、左 directions = [(-1, 0), (0, 1), (1, 0), (0, -1)] # 初始化队列和访问字典 queue = deque([self.start]) visited = {self.start: None} # 存储前驱节点 while queue: current = queue.popleft() if current == self.end: break cy, cx = current for dy, dx in directions: ny, nx = cy + dy, cx + dx # 检查是否在边界内且是通道 if (0 <= ny < self.height and 0 <= nx < self.width and self.maze[ny, nx] == 0 and (ny, nx) not in visited): queue.append((ny, nx)) visited[(ny, nx)] = current # 回溯构建路径 path = [] if self.end in visited: current = self.end while current != self.start: path.append(current) current = visited[current] path.append(self.start) path.reverse() return path def visualize(self, path=None): """可视化迷宫和路径""" plt.figure(figsize=(10, 10)) # 绘制迷宫墙 plt.imshow(self.maze, cmap='binary', interpolation='nearest') # 绘制起点和终点 plt.plot(self.start[1], self.start[0], 'go', markersize=10) # 绿色起点 plt.plot(self.end[1], self.end[0], 'ro', markersize=10) # 红色终点 # 绘制路径 if path: path_y, path_x = zip(*path) plt.plot(path_x, path_y, 'b-', linewidth=2) plt.plot(path_x, path_y, 'yo', markersize=4) # 黄色路径点 plt.xticks([]), plt.yticks([]) plt.show() # 使用示例 if __name__ == "__main__": # 创建迷宫生成器 maze_gen = MazeGenerator(31, 31) # 31x31的迷宫 # 生成迷宫 maze = maze_gen.generate_with_dfs() print("迷宫矩阵示例:") print(maze[:5, :5]) # 打印左上角5x5区域 # 寻找路径 shortest_path = maze_gen.find_path_with_bfs() print(f"\n路径长度: {len(shortest_path)}步") # 可视化结果 maze_gen.visualize(shortest_path) ``` ### 实现说明 1. **迷宫表示** - 使用二维数组(`numpy.ndarray`)表示迷宫 - `1`表示墙,`0`表示通道 - 尺寸为奇数,确保有完整的边界 2. **DFS迷宫生成算法** - 从起点开始,随机选择未访问的相邻位置 - 打通当前位置与下一位置之间的墙 - 使用栈实现回溯机制 - 时间复杂度:$O(height \times width)$ 3. **BFS路径搜索** - 从起点开始广度优先遍历 - 使用队列存储待访问节点 - 记录每个节点的前驱节点用于路径回溯 - 时间复杂度:$O(height \times width)$ 4. **可视化功能** - 使用matplotlib绘制迷宫 - 绿色标记起点,红色标记终点 - 蓝色线条和黄色点标记路径 ### 算法分析 1. **DFS迷宫生成**: - 通过随机选择相邻单元格创建随机迷宫 - 生成的迷宫具有长走廊和死路,保证有唯一路径[^3] - 递归回溯确保所有区域可达[^5] 2. **BFS路径搜索**: - 按层遍历所有可达位置 - 首次到达终点时即为路径 - 保证找到起点到终点的路径[^1] 3. **性能优化**: - 使用队列而非递归实现BFS,避免栈溢出 - 使用集合存储访问状态,提高查找效率 - 路径回溯只需线性时间[^4] ### 应用场景 1. 游戏开发:随机地图生成 2. 路径规划:机器人导航 3. 算法教学:DFS/BFS可视化 4. 网络路由:数据包传输路径优化[^3]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值