本篇若要说难点,就是时间复杂度的把控,还有什么样的解法容易让大家看懂理解
给定一个长度为 n 的非降序数组和一个非负数整数 k ,要求统计 k 在数组中出现的次数
数据范围:0 \le n \le 1000 , 0 \le k \le 1000≤n≤1000,0≤k≤100,数组中每个元素的值满足 0 \le val \le 1000≤val≤100
要求:空间复杂度 O(1),时间复杂度 O(logn)
思路(二分法):由于所需时间复杂度为O(logn),所以可以先通过二分法找到所给的k值,并拿到k值的下标,因为是有序数组,所以由此展开——用left和right分别向左和向右遍历,若与k值相等,则给计数器+1,最后返回计数器即可;
- //计数器
- private int count = 0;
- public int GetNumberOfK(int [] array , int k) {
- //由于时间复杂度为O(logn),所以要利用二分查找先找到这个数
- int len = array.length;
- int left = 0;
- int right = len - 1;
- int keyIndex = binarySearch(array, left, right, k);
- if(count == -1){
- return 0;
- }
- //因为有序,所以分别向两边扩展找相同的元素,找到了,计数就加1
- //左扩展
- left = keyIndex - 1;
- while(left >= 0 && array[left] == k){
- count++;
- left--;
- }
- //右扩展
- right = keyIndex + 1;
- while(right < len && array[right] == k){
- count++;
- right++;
- }
- return count;
- }
- //二分查找
- private int binarySearch(int[] array, int left, int right, int k){
- while(left <= right){
- int mid = (left + right) / 2;
- if(k < array[mid]){
- right = mid - 1;
- }else if(array[mid] < k){
- left = mid + 1;
- }else{
- count++;
- return mid;
- }
- }
- return -1;
- }
在一个二维数组array中(每个一维数组的长度相同),每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。
[
[1,2,8,9],
[2,4,9,12],
[4,7,10,13],
[6,8,11,15]
]
给定 target = 7,返回 true。
给定 target = 3,返回 false。
数据范围:矩阵的长宽满足 0 \le n,m \le 5000≤n,m≤500 , 矩阵中的值满足 0 \le val \le 10^90≤val≤109
进阶:空间复杂度 O(1),时间复杂度 O(n+m)
思路(这题其实非常简单,但此题的标出的难度却是中等,通过率只有百分之二十几?想必大多数人都是因为时间复杂度超过了O(n + m)):为什么简单?二维数组,对每一行进行二分查找就ok~
- public boolean Find(int target, int [][] array) {
- //每一行进行二分查找
- for(int i = 0; i < array.length; i++){
- boolean flay = binarySearch(target, array[i]);
- if(flay){
- return true;
- }
- }
- return false;
- }
- public boolean binarySearch(int target, int[] array){
- int left = 0;
- int right = array.length - 1;
- while(left <= right){
- int mid = (left + right) / 2;
- if(target < array[mid]){
- right = mid - 1;
- }else if(target > array[mid]){
- left = mid + 1;
- }else{
- return true;
- }
- }
- return false;
- }
有一个长度为 n 的非降序数组,比如[1,2,3,4,5],将它进行旋转,即把一个数组最开始的若干个元素搬到数组的末尾,变成一个旋转数组,比如变成了[3,4,5,1,2],或者[4,5,1,2,3]这样的。请问,给定这样一个旋转数组,求数组中的最小值。
数据范围:1 \le n \le 100001≤n≤10000,数组中任意元素的值: 0 \le val \le 100000≤val≤10000
要求:空间复杂度:O(1) ,时间复杂度:O(logn)
思路(二分法):因为数组为非降序数组,所以可以通过二分法,进行循环即可,但要注意以下情况:当mid指向元素大于right指向元素时,说明目标值一定在mid指向的右边;当mid指向元素小于right指向元素时,说明一定在mid指向的左边;若mid指向元素等于right指向元素时,不确定,可以用right缩小范围继续比较;
- public int minNumberInRotateArray(int [] array) {
- int left = 0;
- int right = array.length - 1;
- while(left < right){
- int mid = (left + right) / 2;
- //若中间值大于最右边,说明目标在中间值右边
- if(array[mid] > array[right]){
- left = mid + 1;
- }
- //此时不确定,比如 1 1 1 0 1,所以继续缩小范围
- else if(array[mid] == array[right]){
- right--;
- }
- //不在右边就在左边
- else{
- right = mid;
- }
- }
- return array[left];
- }