找出数组中的峰值
来源:互联网 发布:嘉兴学院雅尔网络课程 编辑:程序博客网 时间:2024/05/17 09:19
这种题目分为两种类型,
1. 找一维数组的峰值
你给出一个整数数组(size为n),其具有以下特点:
- 相邻位置的数字是不同的
- A[0] < A[1] 并且 A[n - 2] > A[n - 1]
假定P是峰值的位置则满足A[P] > A[P-1]
且A[P] > A[P+1]
,返回数组中任意一个峰值的位置。
找一维数组的峰值,最暴力的办法是for循环,逐个元素比较左右两边的值,时间复杂度O(N),.
另外其实最优的算法是二分法,O(log N)
class Solution {public: /** * @param A: An integers array. * @return: return any of peek positions. */ // 1. 第一类面试者 只会 for 循环 int findPeak1(vector<int> A) { // write your code here for(int i = 1; i < A.size()-1; i++){ if(A[i] > A[i-1] && A[i] > A[i+1]){ return i; } } return -1; } // 2. 第二类面试者 知道二分法 int findPeak2(vector<int> A) { if(A.size() < 3){ return -1; } int start = 1; int end = A.size()-1; while(start <= end){ int middle = start + (end - start) / 2; if(A[middle] < A[middle-1]){ end = middle-1; } else if(A[middle] < A[middle+1]){ start = middle+1; } else { return middle; } } return -1;//should never happen } // 3. 第二类面试者 知道二分法(模板解法) int findPeak(vector<int> A) { if(A.size() < 3){ return -1; } int start = 1; int end = A.size()-2; while(start+1 < end){ int middle = start + (end - start) / 2; if(A[middle] < A[middle-1]){ end = middle; } else if(A[middle] < A[middle+1]){ start = middle; } else { start = middle; } } if(A[start] > A[end]){ return start; } return end; }};
2. 找二维数组的峰值
一个整数矩阵有如下一些特性:
- 相邻的整数都是不同的
- 矩阵有 n 行 m 列。
- 对于所有的 i < m, 都有 A[0][i] < A[1][i] && A[n - 2][i] > A[n - 1][i].
- 对于所有的 j < n, 都有 A[j][0] < A[j][1] && A[j][m - 2] > A[j][m - 1].
我们定义一个位置 P 是一个峰,如果有 A[j][i] > A[j+1][i] && A[j][i] > A[j-1][i] && A[j][i] > A[j][i+1] && A[j][i] > A[j][i-1]。
找出该矩阵的一个峰值元素,返回他的坐标
解题思路仍然是二分,可以行二分,也可以列二分,这样时间复杂度O(N log N), 参见下面的解法5最优的方法是行列同时二分 O(N)
class Solution { /** * @param A: An integer matrix * @return: The index of the peak */ // 解法4, 第三类面试者 只会O(N * M)的解法 public List<Integer> findPeakII3(int[][] A) { // write your code here List<Integer> ans = new ArrayList<Integer>(); int n = A.length; int m = A[0].length; for(int i = 1; i < n-1; i++){ for(int j = 1; j < m-1; j++){ int[] dx = {-1, 1, 0, 0}; int[] dy = {0, 0, -1, 1}; if( A[i][j] > A[i+dx[0]][j+dy[0]] && A[i][j] > A[i+dx[1]][j+dy[1]] && A[i][j] > A[i+dx[2]][j+dy[2]] && A[i][j] > A[i+dx[3]][j+dy[3]]){ ans.add(i); ans.add(j); return ans; } } } return ans; } // 解法5, 第四类面试者 会优化,会O(N log N)的解法 public List<Integer> findPeakII4(int[][] A) { List<Integer> ans = new ArrayList<Integer>(); int n = A.length; int m = A[0].length; if(n < 3){ return ans; // argument check } int start = 1, end = n-2; while(start <= end){ int row = start + (end - start) / 2; int col = findLargest(A, row); if(A[row][col] < A[row-1][col]){ end = row - 1; } else if(A[row][col] < A[row+1][col]){ start = row + 1; } else{ ans.add(row); ans.add(col); return ans; } } return ans; } // find largest in a row, return col index public int findLargest(int [][] A, int row){ int col = 0; for(int j = 0; j < A[0].length; j++){ if(A[row][j] > A[row][col]){ col = j; } } return col; } // 解法六, 第五类面试者 会举一反四,会O(N)的解法 public List<Integer> findPeakII(int[][] A) { List<Integer> ans = new ArrayList<Integer>(); int n = A.length; int m = A[0].length; if(n < 3 || m < 3){ return ans; // argument check } int start_row = 1, end_row = n-2; int start_col = 1, end_col = m-2; int row = 0, col = 0; // store middle while(start_row <= end_row && start_col <= end_col){ // search row row = start_row + (end_row - start_row) / 2; col = findLargestInRow(A, row, start_col, end_col); if(A[row][col] < A[row-1][col]){ end_row = row - 1; } else if(A[row][col] < A[row+1][col]){ start_row = row + 1; } else{ ans.add(row); ans.add(col); return ans; } // search column col = start_col + (end_col - start_col) / 2; row = findLargestInCol(A, col, start_row, end_row); if(A[row][col] < A[row][col-1]){ end_col = col - 1; } else if(A[row][col] < A[row][col+1]){ start_col = col + 1; } else{ ans.add(row); ans.add(col); return ans; } } return ans; } // search larget one in a row, return col index public int findLargestInRow(int [][] A, int row, int start_col, int end_col){ int col = start_col; for(int j = start_col; j <= end_col; j++){ if(A[row][j] > A[row][col]){ col = j; } } return col; } // search largest one in a col, return row index; public int findLargestInCol(int [][] A, int col, int start_row, int end_row){ int row = start_row; for(int i = start_row; i <= end_row; i++){ if(A[i][col] > A[row][col]){ row = i; } } return row; }}
最后一种解法是最优的解法,行和列同时二分,同样是利用了一维数组找峰值的思想。时间复杂度是O(N), 为什么呢,下面给出证明:
二分过程中要对行二分扫描中间这一行的最大值,每一行N个数, 然后对列二分找中间一列的最大值,这时候由于之前行二分过,所以每一列只有n/2(或相同数量级)个数,然后再找出(N/2)小矩阵的峰值,这是相同的子问题。于是
T(N) = N + N/2 + T(N/2) = 3/2 * N + O(N)
T(N/2) = 3/2 * (N/2) + O(N/4)
T(N/4) = 3/2 * (N/4) + O(N/8)
T(N/k) = 3/2 * (N/k) + O(1)
以此类推,所有等式相加起来,抵消得到 T(N) = 3/2 * 2N + O(1) = O(N) 。
0 0
- 找出数组中的峰值
- 查找数组中的峰值
- 给定一个数组,找出数组的峰值。返回其下标
- 数组峰值
- 找出数组中的最大值
- 162.Find Peak Element (寻找数组中的峰值点)
- 寻找数组局部峰值
- 寻找数组的峰值
- 找出数组中的Single Number
- 找出数组中的主元素
- 找出一个数组中的”单身“
- 找出二维数组中的鞍点
- 找出数组中的重复元素
- 找出数组中的“单身狗”
- 找出数组中的最大有序子数组
- 找出数组中的唯一重复元素
- 找出数组中的最大值和次大值
- 找出整形数组中的元素最大值。
- java集合类
- Electron-windows下的构建
- Java ServiceLoader(SPI)学习
- 4、第一 个mapReduce程序
- 导航条按钮设置
- 找出数组中的峰值
- JavaScript DOM编程艺术—幻灯片动画
- HDU 5144 NPY and shot (公式+三分)
- sql 提高效率技巧。
- strcpy,strncpy函数实现——string.h库函数
- C++开发中一个解决方案里,两个项目的相互引用,相互依赖的实现方法(解决方法)
- Java学习笔记(内部类、异常)
- ArrayList的操作
- Java NIO教程(上)