IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> 【剑指Offer】二分法例题 -> 正文阅读

[数据结构与算法]【剑指Offer】二分法例题

一、寻找峰值

题目链接

描述:

给定一个长度为n的数组nums,请你找到峰值并返回其索引。数组可能包含多个峰值,在这种情况下,返回任何一个所在位置即可。
1.峰值元素是指其值严格大于左右相邻值的元素。严格大于即不能有等于
2.假设 nums[-1] = nums[n] = ?∞
3.对于所有有效的 i 都有 nums[i] != nums[i + 1]
4.你可以使用O(logN)的时间复杂度实现此问题吗?

数据范围:

1≤nums.length≤2×10^5
?2 ^31<=nums[i]<=2 ^31?1

如输入[2,4,1,2,7,8,4]时,会形成两个山峰,一个是索引为1,峰值为4的山峰,另一个是索引为5,峰值为8的山峰,如下图所示:
在这里插入图片描述

示例1

输入:[2,4,1,2,7,8,4]
返回值:1
说明:4和8都是峰值元素,返回4的索引1或者8的索引5都可以

示例2

输入:[1,2,3,1]
返回值:2
说明:3 是峰值元素,返回其索引 2

思路分析:
这里用到了二分查找的性质,因为数组两边都是无穷小,所以我们只要往高处找就一定能找到波峰。那么我们就可以找一个元素,把数组分成两个区间,每次就走高的一边,最后就能锁定出一个波峰。
在这里插入图片描述

int findPeakElement(int* nums, int numsLen ) {
    // write code here
    int left = 0, right = numsLen - 1;
    while(left < right)
    {
        int mid = (left + right) / 2;
        //右边是往下,不一定有坡峰
        if(nums[mid] > nums[mid + 1])
        {
            right = mid;
        }  
        //右边是往上,一定能找到波峰
        else
        {
            left = mid + 1;
        }
    }
    return left;
}

二、二维数组中的查找

题目链接
描述:

在一个二维数组array中(每个一维数组的长度相同),每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。
[
[1,2,8,9],
[2,4,9,12],
[4,7,10,13],
[6,8,11,15]
]
给定 target = 7,返回 true。
给定 target = 3,返回 false。

数据范围:矩阵的长宽满足 0≤n,m≤500,矩阵中的值满足0≤val≤10^9
进阶:空间复杂度 O(1)O(1) ,时间复杂度 O(n+m)O(n+m)

示例1

输入:7,[[1,2,8,9],[2,4,9,12],[4,7,10,13],[6,8,11,15]]
返回值:true
说明:存在7,返回true

示例2:

输入:1,[[2]]
返回值:false

示例3

输入:3,[[1,2,8,9],[2,4,9,12],[4,7,10,13],[6,8,11,15]]
返回值:false
说明:不存在3,返回false

① 线性搜索

最简单的方法就是暴力遍历,没有用到二维数组的递增性质。
通过规律发现左下角所在元素的所在行最小,所在列最大,那么如果target小于所在元素,就让行--,否则就让列++
在这里插入图片描述

bool Find(int target, int** array, int arrayRowLen, int* arrayColLen ) {
    // write code here
    int row = arrayRowLen - 1, col = 0;
    while(row <= arrayRowLen - 1 && row >= 0 && col <= *arrayColLen - 1 && col >= 0)
    {
        if(array[row][col] == target)
        {
            return true;
        }
        else
        {
            if(array[row][col] < target)
            {
                col++;
            }
            else
            {
                row--;
            }
        }
    }
    return false;
}

② 逐行二分

因为每一行都是有序递增的,所以每一行都能用二分
在这里插入图片描述

bool binary_search(int* arr, int k, int target)
{
    int left = 0, right = k - 1;
    while (left <= right)
    {
        int mid = (right + left) / 2;
        if (arr[mid] == target)
        {
            return true;
        }
        else if (arr[mid] > target)
        {
            right = mid - 1;
        }
        else
        {
            left = mid + 1;
        }
    }
    return false;
}



bool Find(int target, int** array, int arrayRowLen, int* arrayColLen) {
    // write code here
    for (int i = 0; i < arrayRowLen; i++)
    {
        if (binary_search(array[i], *arrayColLen, target))
        {
            return true;
        }
    }
   /*while (arrayRowLen--)
    {
        if (binary_search(*array, *arrayColLen, target))
        {
            return true;
        }
        array++;
    }*/
    return false;
}

三、旋转数组的最小数字

题目链接

描述:

有一个长度为 n 的非降序数组,比如[1,2,3,4,5],将它进行旋转,即把一个数组最开始的若干个元素搬到数组的末尾,变成一个旋转数组,比如变成了[3,4,5,1,2],或者[4,5,1,2,3]这样的。请问,给定这样一个旋转数组,求数组中的最小值。

数据范围:1≤n≤10000,数组中任意元素的值:0≤val≤10000
要求:空间复杂度:O(1)O(1) ,时间复杂度:O(logn)O(logn)

示例1:

输入:[3,4,5,1,2]
返回值:1

示例2:

输入:[3,100,200,3]
返回值:3

思路分析:
这道题其实是二分法的变形,旋转点左边的元素都单调递增且都大于旋转点右边单调递增的元素。
我们的目的是找到旋转点也就是最小的元素,我们可以定义左left、右right指针让他们相遇在旋转点:
arr[mid] > arr[right]
说明mid一定在左递增区间,为了使left移动到旋转点就需要缩小区间,left = mid + 1
arr[mid] < arr[right]
说明mid一定在右递增区间,为了使right移动到旋转点就需要缩小区间,right = mid
但是也有相同元素的情况,例如:{1,0,1,1,1}
这样就无法判断mid在哪个区间了。
那么就让right--,这里不能让left++,因为我们是跟最右边的元素比较,旋转点一定在mid左边。

int minNumberInRotateArray(int* arr, int sz ) {
    // write code here
    if(sz == 0)
    {
        return 0;
    }
    int left = 0, right = sz - 1;
    while(left < right)
    {
        int mid = (left + right) / 2;
        if(arr[mid] > arr[right])
        {
            left = mid + 1;
        }
        else if(arr[mid] < arr[right])
        {
            right = mid;
        }
        else
        {
            right--;
        }
    }
    return arr[left];
}
  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2022-08-06 11:07:37  更:2022-08-06 11:08:07 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/25 23:12:16-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码