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 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> 力扣 (LeetCode)算法基础 -> 正文阅读

[数据结构与算法]力扣 (LeetCode)算法基础

一、二分查找

//二分查找模板
int binarySearch(int[] nums, int target){
    if(nums == null || nums.length == 0) {
        return -1;
    }
    int l = 0, r = nums.length - 1;
    while(l <= r){
        int mid = l + (r - l) / 2; //避免溢出
        if(nums[mid] == target){ 
            return mid; 
        } else if(nums[mid] < target) { 
            l = mid + 1; 
        } else { 
            r = mid - 1; 
        }
    }
    return -1;
}

第一天

第一题:在排序数组中查找元素的第一个和最后一个位置

34.在排序数组中查找元素的第一个和最后一个位置

思路

因为序列已经排序,采用二分查找无疑就是很方便的方法。
一种方式采用二分找到所要求的元素,然后分别向前向后遍历,找第一个出现位置和最后一次出现位置,但这样在特殊情况下比如所有元素均为所求元素时时
间复杂度仍为O(n)。
另一种采用二分进行两次逼近,一次向左逼近,一次向右逼近,找到第一次和最后一次位置,这样保证无论什么情况均为O(logn)

代码

class Solution {
    public int[] searchRange(int[] nums, int target) {
        int left = 0, right = nums.length - 1;
        int[] count = {-1,-1};  //初始化,因要求未找到返回[-1,-1]故初始化为[-1,-1]
        while(left <= right){
            int mid = left + (right - left) / 2; //避免溢出
            if(nums[mid] == target){ // 找到目标元素
                left = mid;
                right = mid;
                while(left >= 0 && nums[left] == target){ //向左遍历,找第一次出现位置
                    left--;
                }
                while(right < nums.length && nums[right] == target){ //向右遍历,找最后一次出现位置
                    right++;
                }
                count[0] = left+1;
                count[1] = right-1;
                break;
            }else if(nums[mid] > target){ //大于目标元素,改变right
                right = mid - 1;
            }else{ //小于目标元素,改变left
                left = mid + 1;
            }
        }
        return count;
    }
}
class Solution {
    public int[] searchRange(int[] nums, int target) {
        int left = 0, right = nums.length - 1;
        int[] count = {-1,-1};
        if(left > right){
            return count;
        }
        while(left < right){
            int mid = left + (right - left) / 2;
            if(nums[mid] >= target){ //向左逼近,只要数不小于目标值就移动right
                right = mid;
            }else{ //小于目标值,移动left
                left = mid + 1;
            }
        }
        if(nums[left] != target){ //因为推出条件不止找到元素还有left和right指针相遇,则需要判断此时数组中对应元素是否为目标元素
            return count;
        }else{
            count[0] = left;
        }

        right = nums.length;
        while(left < right){
            int mid = left + (right - left) / 2;
            if(nums[mid] <= target){ //向右逼近,只要数不大于目标值就移动left
                left = mid+1;
            }else{ //大于目标值移动right
                right = mid;
            }
        }
        count[1] = left - 1;
        return count;
    }
}

第二题:搜索旋转排序数组

33.搜索旋转排序数组

思路

因为排序数组进行了旋转也就是移位,使得二分中简单的判断已经不符合要求,需要加入新的判断条件来判断目标元素在中间下标之前还是之后。
当中间下标元素值小于目标元素时,如果目标元素也小于或等于右指针下标元素,则说明目标若存在,则必在中间下标与右指针下标之间,移动左指针,反之
如果目标元素大于右指针下标元素,则说明目标若存在,则必在中间下标与左指针下标之间,移动右指针。
当中间下标元素值大于目标元素时分析同理,与左指针下标元素比较,如果目标元素也大于或等于左指针下标元素,移动右指针,反之移动左指针

代码

class Solution {
    public int search(int[] nums, int target) {
        int low = 0;
        int high = nums.length - 1;
        while(low <= high){
            int mid = low + (high - low) / 2; //防止溢出
            if(nums[mid] == target){
                return mid;
            }else if(nums[mid] < nums[high]){
                if(nums[mid] < target && target <= nums[high]){ //目标中间下标与右指针下标之间
                    low = mid + 1;
                }else{ //目标中间下标与左指针下标之间
                    high = mid - 1;
                }
            }else{ //目标中间下标与左指针下标之间
                if(nums[low] <= target && nums[mid] > target){
                    high = mid - 1;
                }else{ //目标中间下标与右指针下标之间
                    low = mid + 1;
                }
            }
        }
        return -1;
    }
}

第三题:搜索二维矩阵

74.搜索二维矩阵

思路

标准的二分搜索题,数组变成了二维,但按题意按行先的话元素依然是标准的升序的,现在用左右指针表示行先的元素的位置,则中间位置的行数下标为中间
位置除以列数的商,列数下标为中间位置除以列数的余数。

代码

class Solution {
    public boolean searchMatrix(int[][] matrix, int target) {
        if(matrix.length == 0 || matrix[0].length == 0){
            return false;
        }
        int m = matrix.length,n = matrix[0].length; //计算行数和列数
        int low = 0,high = m * n - 1; //计算元素总个数
        while(low <= high){
            int mid = low + (high - low) / 2; //防止溢出
            int i = mid / n; //计算中间位置的行数下标
            int j = mid % n; //计算中间元素的列数下标
            if(matrix[i][j] == target){
                return true;
            }else if(matrix[i][j] < target){
                low = mid + 1;
            }else{
                high = mid - 1;
            }
        }
        return false;
    }
}

第二天

第四题:寻找旋转排序数组中的最小值

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

思路

排序数组旋转之后的数组无非就是两段升序的数组,从开始到中间某一个数为升序,然后接着就是最小数到最后的一个升序,找最小值就是找第二个升序数组
的开始小标,因元素互不相同可知第二个升序数组的最大值是小于第一个升序数组最小值的。所以采用二分法时,若中间位置的元素大于或等于0下标元素,
则说明中间元素在第一个升序数组中,则移动左指针,否则移动右指针。
因为旋转次数可能为数组长度的整数倍,这时数组整体为升序,找第二个升序数组的开始下标会找到数组末尾,这恰恰是最大的元素,因此,在完成二分查找
后,还应与数组第一个元素进行比较,如果第一个元素更小应返回第一个元素。

代码

class Solution {
    public int findMin(int[] nums) {
        int l = 0, r = nums.length - 1;
        while(l < r){
            int mid = l + (r - l) / 2; //防止溢出
            if(nums[mid] >= nums[0]){ //大于首元素,在第一个升序数组段中移动l
                l = mid + 1;
            }else{
                r = mid;
            }
        }
        return nums[l] < nums[0]?nums[l]:nums[0]; //与首元素进行比较
    }
}

第五题:寻找峰值

162.寻找峰值

思路

本题可以理解为找函数的极大值点,由于nums[-1] = nums[n] = -∞的存在,可知必然存在极大值点。
当采用二分算法时,如果中间位置大于下一个元素,则可知在中间位置到下一个位置是下降的,因为nums[-1] = -∞,则可知在左指针位置到中间位置必有先
上升后下降,即必有大极点,则移动右指针。如果中间位置小于下一个元素,则可知在中间位置到下一个位置是上升的,因为nums[n] = -∞,则可知在中间
位置到右指针必是先上升后下降,即必有极大点,则移动左指针。

代码

class Solution {
    public int findPeakElement(int[] nums) {
        int l = 0, r = nums.length - 1;
        while(l < r){
            int mid = l + (r - l) / 2; //防止溢出
            if(nums[mid] > nums[mid + 1]){ //左边必有极大点
                r = mid;
            }else{ //左边必有极大点
                l = mid + 1;
            }
        }
        return l;
    }
}
  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2021-07-30 12:59:14  更:2021-07-30 13:00:37 
 
开发: 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年5日历 -2024/5/3 18:32:16-

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