【Java 优选算法】二分算法(下)

欢迎关注个人主页:逸狼


创造不易,可以点点赞吗~

如有错误,欢迎指出~



山脉数组的顶峰索引

题目链接

解法

小细节:根据题目特性,山脉数组的第一个数和最后一个数一定不是峰值

暴力枚举O(n):按顺序遍历,当遇到一个数x比后面的数大时,返回x的索引

解法二: 二分查找算法 ,利用山脉数组的二段性,将数组分为arri > arri - 1和arri < arri - 1两部分

画图举例

代码

复制代码
class Solution {
    public int peakIndexInMountainArray(int[] arr) {
        int left = 1, right = arr.length - 2;
        while(left < right){
            int mid = left + (right - left + 1) / 2;
            if(arr[mid] > arr[mid - 1]) left = mid;
            else right = mid - 1;
        }
        return left;
    }
}

寻找峰值

题目链接

解法

根据题目得出可能有多个,得出一个就行,所以我们可以选择求数组 出现的第一个峰值

暴力解法O(n): 从第一个位置开始遍历,一直走,分情况讨论,分三种

  1. 第一个数最大,往后走 数逐渐减小
  2. 数先上升再下降,下降的前一个数为峰值
  3. 数一直上升,最后一个数为峰值

解法二: 二分查找算法, 利用二段性,分两种情况

数组开始呈下降趋势,即arrmid > arrmid + 1, 得出峰值在左边区间,right = mid

数组开始呈上升趋势,即arrmid < arrmid + 1, 峰值在右边区间,left = mid + 1

画图举例

代码

复制代码
class Solution {
    public int findPeakElement(int[] nums) {
        int left = 0, right = nums.length - 1;
        while(left < right){
            int mid = left + (right - left) / 2;
            if(nums[mid] > nums[mid + 1]) right = mid;
            else left = mid + 1;
        }
        return left;
    }
}

寻找旋转排序数组中最小值

题目链接

解法

理解题目: 旋转(一次)的意思就是把数组中最后一个数 放到第一个位置

暴力解法O(n): 从前往后遍历数组找到最小值

解法二: 利用二段性将数组分为两段,AB段和CD段,都是呈上升趋势,且CD段最后一个值(标记为 x )小于AB段的值,所以找最小值 要到CD段里找.

当arrmid > x,说明此时mid在AB段,更新left= mid+ 1;

当arrmid < x,说明此时mid在CD段,更新right= mid;

画图举例

代码

复制代码
class Solution {
    public int findMin(int[] nums) {
        int left = 0, right = nums.length - 1;
        int x =nums[right];//标记最后位置的值
        while(left < right){
            int mid = left + (right - left) / 2;
            if(nums[mid] > x) left = mid + 1;
            else right = mid;
        }
        return nums[left];
    }
}

点名

题目链接

解法

解法有很多种:1.利用哈希表 , 2.直接遍历找结果 3.位运算,异或,将题给数组与完整数组异或

4.等差求和,求出完整数组的和,再减去题给的数组的和,得出的就是缺失的数 . 上面的这4种解法时间复杂度都是O(n)

二分查找算法:找出数组的二段性,左边区间数组的值等于下标,右边区间不等于,找出第一个不等于数组值的下标即可

  • 左区间: numsmid == mid 更新left = mid + 1;
  • 右区间: numsmid != mid 更新 right = mid;

细节处理:当题给的数组是一个 完全递增的数组,缺的数是left+1

画图举例

代码

复制代码
class Solution {
    public int takeAttendance(int[] records) {
        int left = 0, right = records.length - 1;
        while(left < right){
            int mid = left + (right - left) / 2;
            if(records[mid] == mid) left = mid + 1;
            else right = mid;
        }
        if(left == records[left]) return left + 1;
        return left;
    }
}
相关推荐
晚风醉蝶1 小时前
1-11-奇偶排序-OddEvenSort
java·数据结构·算法
旖旎夜光1 小时前
LeetCode 852:山脉数组的峰顶索引(二分查找) —— 题解
数据结构·c++·算法·leetcode·二分查找
小雪崩3 小时前
嵌入式学习 day25:哈希表及排序与查找
linux·c语言·数据结构·学习·排序算法
_Narcissus_5 小时前
动态规划初探(含完整代码实现)
c语言·数据结构·c++·算法·动态规划·背包问题·最短路径
_Narcissus_7 小时前
枚举和模拟算法笔记
c语言·数据结构·c++·笔记·算法·模拟·枚举
冻柠檬飞冰走茶8 小时前
《数据结构实验指导-C++语言版》 在顺序表 list 中查找元素 x
开发语言·数据结构·c++·算法·list
Brilliantwxx8 小时前
【C++】 高阶数据结构图(1)并查集
开发语言·数据结构·c++
Fa_Mian_Tuan8 小时前
最小生成树之Kruskal算法(超详细原理+完整可运行C语言代码)
c语言·开发语言·数据结构·笔记·算法·图论
冻柠檬飞冰走茶8 小时前
《数据结构实验指导-C++语言版》 返回单链表 list 中第 i 个元素值
开发语言·数据结构·c++·算法·list
LuminousCPP10 小时前
栈和队列专题(四):LeetCode 232. 用栈实现队列|双栈分工 + 按需迁移 + 摊还 O(1)
c语言·数据结构·笔记·算法·leetcode