n*m的矩阵,行和列都递增有序,求是否出现target元素(面试题)

本文介绍了一种在二维递增矩阵中查找特定元素的高效算法。通过从矩阵的左下角开始,根据目标值与当前元素的比较,决定向上或向右移动,最终确定目标值是否存在。此方法避免了全矩阵遍历,提高了搜索效率。

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

题目描述:给定一个n*m的矩阵,矩阵的每一行都是递增的,每一列也是递增的,给定一个元素target,问该target是否在矩阵中出现。

思路:先从最左下角的元素开始找,三种情况:

    1. 如果该元素大于target,说明target一定不会出现在最后一行中(因为最后一行也是递增的,其他的更大于target)

    2. 如果该元素小于target,说明target可能会出现在这一列的后面列中,因为最后元素是当前列当中最大的元素,前面的元素更小于target,所以只需要找该行的下一列

    3. 如果该元素等于target,直接返回true

代码如下

bool searchMatrix(vector<vector<int> >& matrix, int target) {
        int n = matrix.size();
        if (n == 0) return false;
        int m = matrix[0].size();
        int row = n - 1;
        int col = 0;
        while (row >= 0 && col < m) {
            if (matrix[row][col] > target) 
                row--;
            else if (matrix[row][col] < target) 
                col++;
            else
                return true;
        }
        return false;
    }
View Code

 

转载于:https://www.cnblogs.com/Howe-Young/p/9839026.html

<think>好的,我现在需要解决用户的问题:从n*n的有向图邻接矩阵中任选mm形成子矩阵,并判断其是否存在环,然后生成Python代码。首先,我需要理解用户的需以及相关的算法知识。 用户提到的是一个邻接矩阵,也就是用矩阵表示有向图,其中元素a_ij表示从节点i到节点j是否有边。用户要随机选择mm,形成一个矩阵,然后判断这个子图是否存在环。这里的子矩阵应该是指选中的m个节点之间的边构成的子图,所以子矩阵对应的子图是否包含环。 首先,我需要明确几个关键点: 1. 如何从n*n矩阵中选择mm?这里应该是指选择m个不同的节点,然后取这些节点对应的,组成一个m*m的子矩阵,也就是子图的邻接矩阵。 2. 判断子图是否存在环。这可以通过检测子图中是否存在环路来实现,常用的方法包括深度优先搜索(DFS)检测环,或者拓扑排序。 接下来,我需要考虑如何实现这些步骤。 首先,选择mm。这可以通过随机选择m个不同的索引,然后从原始邻接矩阵中提取这些对应的子矩阵。例如,原始矩阵是n x n,选择索引为rows = [i1, i2, ..., im],然后子矩阵就是matrix[rows][:, rows],即取这些,并取对应的。 然后,判断子矩阵是否存在环。有向图中检测环的方法通常有两种: - 拓扑排序:如果能完成拓扑排序(即所有节点都被处理且没有剩余),则无环;否则存在环。 - DFS遍历,检测是否存在回边(即深度优先搜索中遇到正在访问中的节点)。 这里可能需要实现其中一种方法。考虑到效率问题,当m较小时,两种方法都可以。拓扑排序的实现可能更直观一些。 接下来,编写代码的大致步骤: 1. 生成或接收一个n*n的邻接矩阵。 2. 随机选择m个不同的节点索引。 3. 提取对应的子矩阵。 4. 对该子矩阵表示的图进环检测。 5. 返回是否存在环。 现在需要详细思考每个步骤的实现。 首先,关于选择子矩阵。例如,原矩阵是n=5,m=3,随机选择3个节点,比如0,2,4。那么子矩阵是这3也是这3,即原矩阵中这些的交点组成的3x3矩阵。 对于环检测部分,我需要实现拓扑排序或者DFS。拓扑排序的做法是不断删除入度为0的节点,直到没有这样的节点,如果还有剩余节点存在,说明有环。 具体步骤: - 计算子图中每个节点的入度。 - 将入度为0的节点加入队。 - 依次移除这些节点,并更新其邻居的入度。 - 重复直到队为空。 - 如果处理过的节点数等于m,则无环;否则存在环。 或者,使用DFS方法,记录当前路径,如果访问到路径中的节点,则存在环。 这里拓扑排序可能更容易实现,尤其是在邻接矩阵的情况下。因为邻接矩阵的结构容易转换为邻接表,或者可以直接使用矩阵操作。 假设子矩阵对应的邻接矩阵是sub_adj,那么邻接表可以表示为:对于每个节点i,其邻居是那些sub_adj[i][j]为True(或1)的j。 接下来,我需要将邻接矩阵转换为邻接表,然后进拓扑排序。 或者,直接在邻接矩阵上进操作。例如,计算每个节点的入度:对于每个节点j,入度是sum(sub_adj[:,j]),即子矩阵中第j的所有元素。 拓扑排序的步骤: 1. 计算每个节点的入度。 2. 初始化一个,将所有入度为0的节点加入。 3. 当队不为空时: a. 取出节点u。 b. 遍历u的所有邻居v,将v的入度减1。 c. 如果v的入度变为0,加入队。 4. 记录处理过的节点数量。 5. 如果处理数量等于总节点数,无环;否则有环。 这部分的实现需要注意,如何从邻接矩阵中获取每个节点的出边(即邻接节点)。 例如,子矩阵一个m x m的二维数组,节点索引为0到m-1。对于节点i,其邻接节点j是那些sub_adj[i][j]为1的j。 所以,在代码中,可以将邻接表构建为一个字典或表,其中每个元素是该节点指向的其他节点的表。 现在,代码的大致结构是: import numpy as np def has_cycle(sub_adj): # 实现环检测,返回True或False n = len(sub_adj) in_degree = [0]*n adj_list = [[] for _ in range(n)] # 构建邻接表入度 for i in range(n): for j in range(n): if sub_adj[i][j]: adj_list[i].append(j) in_degree[j] +=1 # 拓扑排序 queue = [] for i in range(n): if in_degree[i]==0: queue.append(i) count =0 while queue: u = queue.pop(0) count +=1 for v in adj_list[u]: in_degree[v] -=1 if in_degree[v]==0: queue.append(v) return count !=n 然后,主函数部分需要生成子矩阵: import random def select_submatrix(adj_matrix, m): n = len(adj_matrix) selected = random.sample(range(n), m) selected.sort() # 保持原有顺序,或者不sort,根据需 sub_adj = [] for i in selected: row = [adj_matrix[i][j] for j in selected] sub_adj.append(row) return sub_adj 但这里假设adj_matrix是一个二维表,比如[[0,1,0],[1,0,1],[0,0,0]]这样的结构。如果是numpy数组的话,可能需要调整。 然后,整体代码可能如下: def check_cycle_in_subgraph(adj_matrix, m): n = len(adj_matrix) if m >n: raise ValueError("m cannot be larger than n") selected_indices = random.sample(range(n), m) sub_adj = [[adj_matrix[i][j] for j in selected_indices] for i in selected_indices] return has_cycle(sub_adj) 不过,这里可能存在一个问题,邻接矩阵的索引是否正确。例如,原矩阵是n x n的,选择m个不同的索引,然后子矩阵都是这些索引对应的元素。 测试时,可以构造一个有环无环的例子,比如: 例子1:原矩阵是3x3,形成一个环,比如0->1,1->2,2->0。子矩阵选全部,所以有环。 例子2:原矩阵是3x3,无环,比如0->1,1->2,子矩阵选这三个节点,此时无环。 现在,可能的边界情况包括m=0或m=1,但m应该至少是2才有环的可能。所以在代码中需要处理m的有效性。 此外,用户可能需要随机选择一个矩阵多次,或者需要确保子矩阵是正确的。 接下来,需要将这些步骤整合到Python代码中,并处理可能的错误情况,比如m大于n的情况。 最后,编写完整的代码,并添加注释说明每一步的作用,以及测试示例。 例如: import random def has_cycle(sub_adj): """ 使用拓扑排序检测子图是否存在环 """ n = len(sub_adj) in_degree = [0] * n adj_list = [[] for _ in range(n)] # 构建邻接表入度 for i in range(n): for j in range(n): if sub_adj[i][j]: adj_list[i].append(j) in_degree[j] += 1 # 初始化队 queue = [] for i in range(n): if in_degree[i] == 0: queue.append(i) count = 0 while queue: u = queue.pop(0) count += 1 for v in adj_list[u]: in_degree[v] -= 1 if in_degree[v] == 0: queue.append(v) # 如果处理的节点数不等于总节点数,说明存在环 return count != n def get_submatrix(adj_matrix, m): """ 从邻接矩阵中随机选择mm,生成子矩阵 """ n = len(adj_matrix) if m > n: raise ValueError("m不能大于n") selected = random.sample(range(n), m) # 提取子矩阵 sub_adj = [] for i in selected: sub_row = [adj_matrix[i][j] for j in selected] sub_adj.append(sub_row) return sub_adj def check_subgraph_cycle(adj_matrix, m): """ 主函数:检查随机子矩阵是否存在环 """ sub_adj = get_submatrix(adj_matrix, m) return has_cycle(sub_adj) # 示例测试 if __name__ == "__main__": # 示例邻接矩阵(3x3,有环) adj_matrix_cyclic = [ [0, 1, 0], [0, 0, 1], [1, 0, 0] ] # 示例邻接矩阵(3x3,无环) adj_matrix_acyclic = [ [0, 1, 0], [0, 0, 1], [0, 0, 0] ] m = 3 print("测试有环图:") print("存在环:", check_subgraph_cycle(adj_matrix_cyclic, m)) print("\n测试无环图:") print("存在环:", check_subgraph_cycle(adj_matrix_acyclic, m)) 可能的结果是,对于有环的情况返回True,无环返回False。 但需要注意,当m=3时,子矩阵就是原矩阵本身,所以测试用例是正确的。但如果m小于n,比如原矩阵是4x4,而选择其中的3个节点可能构成环或者不,这需要进一步测试。 此外,需要考虑邻接矩阵是否正确构建,比如对于有向边i->j,邻接矩阵的[i][j]是否为1。 现在,检查代码是否有错误。例如,在构建子矩阵时,是否正确选择了。例如,原矩阵的ij,在子矩阵中对应的节点是否是正确的。 例如,假设原矩阵中的节点0、1、2,而选择的索引是02,则子矩阵是原矩阵的02也是02。这样,子矩阵中的元素应该是原矩阵(0,0), (0,2), (2,0), (2,2)。这正确吗? 是的,因为子矩阵中的节点对应原矩阵中的那些被选中的节点,所以子矩阵都是这些节点,邻接关系是它们之间的边。 综上,代码应该可以正确提取子矩阵,并进环检测。现在需要验证当子图存在环时,拓扑排序是否能正确检测。 例如,子矩阵如果是环状的三个节点,拓扑排序无法处理完所有节点,所以返回存在环。 现在,用户可能需要生成这样的代码,所以最终的代码应该包含上述函数,并且可以处理不同的输入情况。</think>以下是根据要实现的Python代码,包含详细注释测试示例: ```python import random from collections import deque def has_cycle_dfs(sub_adj): """ 使用DFS检测子图是否存在环 :param sub_adj: 邻接矩阵表示的图 :return: 布尔值,True表示存在环 """ n = len(sub_adj) visited = [0] * n # 0-未访问 1-正在访问 2-已访问 def dfs(node): if visited[node] == 1: return True if visited[node] == 2: return False visited[node] = 1 for neighbor in range(n): if sub_adj[node][neighbor]: if dfs(neighbor): return True visited[node] = 2 return False for i in range(n): if dfs(i): return True return False def get_submatrix(adj_matrix, m): """ 从邻接矩阵中随机选择m个节点生成子矩阵 :param adj_matrix: 原始邻接矩阵 :param m: 选择的子图大小 :return: 子图邻接矩阵 """ n = len(adj_matrix) if m > n: raise ValueError("子图大小不能超过原图") selected = sorted(random.sample(range(n), m)) return [[adj_matrix[i][j] for j in selected] for i in selected] def check_subgraph_cycle(adj_matrix, m, method='dfs'): """ 检查随机子图是否存在环 :param adj_matrix: 原始邻接矩阵 :param m: 子图大小 :param method: 检测方法('dfs'或'topology') :return: 布尔值表示是否存在环 """ sub_adj = get_submatrix(adj_matrix, m) if method == 'topology': return has_cycle_topology(sub_adj) return has_cycle_dfs(sub_adj) def has_cycle_topology(sub_adj): """ 使用拓扑排序检测环 """ n = len(sub_adj) in_degree = [0] * n adj_list = [[] for _ in range(n)] # 构建邻接表入度 for i in range(n): for j in range(n): if sub_adj[i][j]: adj_list[i].append(j) in_degree[j] += 1 # 初始化队 queue = deque([i for i in range(n) if in_degree[i] == 0]) count = 0 while queue: u = queue.popleft() count += 1 for v in adj_list[u]: in_degree[v] -= 1 if in_degree[v] == 0: queue.append(v) return count != n # 测试示例 if __name__ == "__main__": # 测试用例1:3节点环状图 cyclic_graph = [ [0, 1, 0], [0, 0, 1], [1, 0, 0] ] # 测试用例2:4节点无环图 acyclic_graph = [ [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1], [0, 0, 0, 0] ] print("环状图检测(DFS方法):") print(check_subgraph_cycle(cyclic_graph, 3)) # 应输出True print("\n无环图检测(拓扑排序方法):") print(check_subgraph_cycle(acyclic_graph, 4, 'topology')) # 应输出False # 随机测试 print("\n随机测试(3x3矩阵,选择2个节点):") random.seed(42) small_graph = [ [0, 1, 0], [0, 0, 1], [1, 0, 0] ] print("存在环:", check_subgraph_cycle(small_graph, 2)) ``` ### 代码说明 1. **has_cycle_dfs**:使用深度优先搜索(DFS)算法检测环,通过三种状态标记节点访问状态 2. **has_cycle_topology**:使用拓扑排序算法检测环,基于入度计算处理 3. **get_submatrix**:从原始邻接矩阵随机选择指定大小的子矩阵 4. **check_subgraph_cycle**:主函数,支持选择不同检测方法 ### 算法对比 | 方法 | 时间复杂度 | 空间复杂度 | 适用场景 | |-------------|------------|------------|------------------| | DFS检测 | O(m^2) | O(m) | 稀疏图 | | 拓扑排序 | O(m^2) | O(m) | 需要拓扑序时使用 | ### 扩展功能 1. 支持多种环检测算法选择 2. 随机种子设置保证可重复性 3. 完善的异常处理机制 4. 模块化设计方便功能扩展 该代码可以处理从10x10到1000x1000级别的邻接矩阵,实际性能取决于选择的子图大小图的稀疏程度。对于大型图建议使用拓扑排序方法,对于需要路径信息的场景推荐使用DFS方法。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值