面试经典150题【131-140】

news2024/11/24 13:58:07

文章目录

  • 面试经典150题【131-140】
    • 123.买卖股票的最佳时机III
    • 188.买卖股票的最佳时机IV
    • 二分查找的板子:
    • 35.搜索插入位置
    • 74.搜索二维矩阵
    • 162.寻找峰值
    • 33.搜索旋转排序数组
    • 34.在排序数组中查找元素的第一个和最后一个位置
    • 153.寻找旋转排序数组中的最小值
    • 4.寻找两个正序数组的中位数

面试经典150题【131-140】

123.买卖股票的最佳时机III

在这里插入图片描述
buy1代表第一次买,sell1代表第一次卖。
buy2代表第二次买,sell2代表第二次卖。
每个值的最大值/迭代值,都与上一个商业操作有关。
同一天买入卖出不影响,因为利润为0

class Solution {
    public int maxProfit(int[] prices) {
        int buy1=-prices[0],sell1=0;
        int buy2=-prices[0],sell2=0;
        for(int i=0;i<prices.length;i++){
            buy1=Math.max(buy1,-prices[i]);
            sell1=Math.max(sell1,buy1+prices[i]);
            buy2=Math.max(buy2,sell1-prices[i]);
            sell2=Math.max(sell2,buy2+prices[i]);
        }
        return sell2;
    }
}

188.买卖股票的最佳时机IV

在这里插入图片描述

class Solution {
    public int maxProfit(int k, int[] prices) {
        if (prices.length == 0) {
            return 0;
        }

        int n = prices.length;
        //k = Math.min(k, n / 2);
        int[] buy = new int[k];
        int[] sell = new int[k];
        Arrays.fill(buy,-prices[0]);
        Arrays.fill(sell,0);
       
        for (int i = 0; i < n; ++i) {
            buy[0]=Math.max(buy[0],-prices[i]);
            sell[0]=Math.max(sell[0],buy[0]+prices[i]);
            for (int j = 1; j < k; ++j) {
                buy[j] = Math.max(buy[j], sell[j-1] - prices[i]);
                sell[j] = Math.max(sell[j], buy[j] + prices[i]);
            }
        }

        return Arrays.stream(sell).max().getAsInt();
    }
}

无需考虑同一天的买卖和k值与n/2的问题,直接模版梭哈。
在一轮i的循环中,对无数个buy和sell赋值即可
注意要对buy和sell初始化。

二分查找的板子:

小于等于的

class Solution {
    public int searchInsert(int[] nums, int target) {
        int left = 0, right = nums.length - 1; // 注意
        while(left <= right) { // 注意
            int mid = (left + right) / 2; // 注意
            if(nums[mid] == target) { // 注意
                // 相关逻辑
            } else if(nums[mid] < target) {
                left = mid + 1; // 注意
            } else {
                right = mid - 1; // 注意
            }
        }
        // 相关返回值
        return ?;
    }
}

小于的

class Solution {
    public int searchInsert(int[] nums, int target) {
        int left = 0, right = nums.length; // 注意
        while(left < right) { // 注意
            int mid = (left + right) / 2; // 注意
            if(nums[mid] == target) {
                // 相关逻辑
            } else if(nums[mid] < target) {
                left = mid + 1; // 注意
            } else {
                right = mid; // 注意
            }
        }
        // 相关返回值
        return ?;
    }
}

然后我们看一下Java内置的Arrays.binarySearch的方法:

    private static int binarySearch0(int[] a, int fromIndex, int toIndex,
                                     int key) {
        int low = fromIndex;
        int high = toIndex - 1;

        while (low <= high) {
            int mid = (low + high) >>> 1;
            int midVal = a[mid];

            if (midVal < key)
                low = mid + 1;
            else if (midVal > key)
                high = mid - 1;
            else
                return mid; // key found
        }
        return -(low + 1);  // key not found.
    }

我们可以发现他就是用的小于等于的模版,只不过最后的return的时候有些特别。

35.搜索插入位置

在这里插入图片描述

class Solution {
    public int searchInsert(int[] nums, int target) {
        int left = 0, right = nums.length - 1;
        while (left <= right) {
            int mid = left + (right - left) / 2;
            if (nums[mid] == target)
                return mid;
            if (nums[mid] > target)
                right = mid - 1;
            if (nums[mid] < target)
                left = mid + 1;
        }
        return left;

    }
}

74.搜索二维矩阵

在这里插入图片描述
在这里插入图片描述
先往下搜索找到具体的行,再往右搜索找具体的值。
但是这个题咔咔错
在这里插入图片描述
首先用找到target左边的元素的方法,然后再用标准二分查找有没有这个元素即可。

class Solution {
    public  boolean searchMatrix(int[][] matrix, int target) {
        int len1 = matrix.length, len2 = matrix[0].length;
        int index = binarySearchFirstColumn(matrix,target);
        if(index<0) return false;
        if (matrix[index][0] == target)
            return true;
        int[] matrixRow = new int[len2];
        for (int i = 0; i < len2; i++) {
            matrixRow[i] = matrix[index][i];
        }
        int ans = Arrays.binarySearch(matrixRow, target);
        if (ans < 0)
            return false;
        else
            return true;
    }

    public int binarySearchFirstColumn(int[][] matrix, int target) {
        int low = 0, high = matrix.length - 1;
        while (low <= high) {
            int mid = (high - low ) / 2 + low;
            if(matrix[mid][0]==target) return mid;
            if (matrix[mid][0] < target) {
                low = mid+1 ;
            } else {
                high = mid - 1;
            }
        }

        return high<0? 0:high;
    }


}

尤其是这个找第一列,最后的return很特别。是判断high是否小于0
这种是寻找小于等于目标值的最右边的索引。return high<0? 0:high

162.寻找峰值

在这里插入图片描述

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

    }
}

对于1,4,5,6,2,7,8,9,10来说,
只要数组中存在一个元素比相邻元素大,那么沿着它一定可以找到一个峰值。2<7.则最后答案是10.

33.搜索旋转排序数组

nums是升序的。
在这里插入图片描述

class Solution {
    public int search(int[] nums, int target) {
        int left = 0, right = nums.length - 1, mid = 0;
        while (left <= right) {
            mid = (left + right) / 2;
            if (target == nums[mid])
                return mid;
            // mid在左区间里
            if (nums[mid] >= nums[left]) {

                if (target >= nums[left] && target < nums[mid]) {
                    // target在mid的左边
                    right = mid - 1;
                } else {
                    left = mid + 1;
                }

            } else {
                if (target > nums[mid] && target <= nums[right]) {
                    left = mid + 1;
                } else {
                    right = mid - 1;
                }
            }
        }
        return -1;

    }
}

旋转以后,肯定是4567123,nums[0]一定比后面的右段大
先判断nums[mid]和nums[0]的关系,判断是在左段(数值比较大的一段)还是右段(数值比较小的一段)
然后比较target和nums[mid]的关系,判断他在mid的左边还是右边。

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

在这里插入图片描述

class Solution {
    public int[] searchRange(int[] nums, int target) {
        int left = 0;
        int right = nums.length - 1;
        int first = -1;
        int last = -1;
        // 找第一个等于target的位置
        while (left <= right) {
            int middle = (left + right) / 2;
            if (nums[middle] == target) {
                first = middle;
                right = middle - 1; // 重点
            } else if (nums[middle] > target) {
                right = middle - 1;
            } else {
                left = middle + 1;
            }
        }
        // 最后一个等于target的位置
        left = 0;
        right = nums.length - 1;
        while (left <= right) {
            int middle = (left + right) / 2;
            if (nums[middle] == target) {
                last = middle;
                left = middle + 1; // 重点
            } else if (nums[middle] > target) {
                right = middle - 1;
            } else {
                left = middle + 1;
            }
        }
        return new int[] { first, last };
    }
}

以找最左边的first为例,即使找到了,也要再做一次right = mid-1;继续遍历。直到不等于(即越界)

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

在这里插入图片描述
一定要理解旋转数组是一个数字大的前半段和一个数字小的后半段。
如果nums[mid]>nums[right] ,说明mid在左半段,则left=mid+1
右边不能-1,万一右半段只有一个数字。
当然如果nums[left]<nums[mid],这说明nums[left]就是最小值了。

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


    }
}

4.寻找两个正序数组的中位数

在这里插入图片描述
当 [ [a1],[b1,b2,b3] | [a2,…an],[b4,…bn] ]

我们只需要比较 b3 和 a2 的关系的大小,就可以知道这种分法是不是准确的!

例如:我们令:

nums1 = [-1,1,3,5,7,9]

nums2 = [2,4,6,8,10,12,14,16]

当 m1 = 4,m2 = 3 ,它的中位数就是median = (num1[m1] + num2[m2])/2

时间复杂度:O(log(min(m,n)))

class Solution {
    public double findMedianSortedArrays(int[] nums1, int[] nums2) {
        int n1 = nums1.length;
        int n2 = nums2.length;
        if (n1>n2)
            return findMedianSortedArrays(nums2, nums1);
        //对于6+8而言,k=7 0-7和8-15. 对于6+7而言,K还是7,0-6,7,8-14
        int k = (n1 + n2 + 1)/2;
        int left = 0;
        //这个right也设置的很巧妙。
        int right = n1;
        //这里的left和right都是对于短的nums1而言的。
        while(left < right){
            int m1 = left +(right - left)/2;
            int m2 = k - m1;
            if (nums1[m1] < nums2[m2-1])
                left = m1 + 1;
            else
                right = m1;
        }
        //这样对于7+7的来说,m1=7,m2=0
        //对于 6+7而言,K=7,m1=6,m2=1
        int m1=left,m2=k-left;
        int c1 = Math.max(m1 <= 0 ? Integer.MIN_VALUE : nums1[m1-1],
                         m2 <= 0 ? Integer.MIN_VALUE : nums2[m2-1]);
        if ((n1 + n2) % 2 == 1)
            return c1;
        int c2 = Math.min( m1 >= n1 ? Integer.MAX_VALUE :nums1[m1],
                         m2 >= n2 ? Integer.MAX_VALUE : nums2[m2]);
        return (c1 + c2) * 0.5;

    }
}

感觉二分这边就很恶心。上一道题就需要设置right=n1才行。然而大部分题是设置right=n1-1;
需要控制好很多边界变量的设置,即使会了板子也不一定能搞出来。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1566046.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

C++之类和对象的中篇

&#x1d649;&#x1d65e;&#x1d658;&#x1d65a;!!&#x1f44f;&#x1f3fb;‧✧̣̥̇‧✦&#x1f44f;&#x1f3fb;‧✧̣̥̇‧✦ &#x1f44f;&#x1f3fb;‧✧̣̥̇:Solitary_walk ⸝⋆ ━━━┓ - 个性标签 - &#xff1a;来于“云”的“羽球人”。…

函数参数缺省和内联函数【C++】

文章目录 函数参数缺省函数参数缺省的条件和要求 内联函数内联函数的工作原理内联函数的定义方法内联函数的要求解决方法&#xff1a;直接在.h中定义内联函数的函数体 内联函数再Debug模式下默认是不展开的 函数参数缺省 顾名思义&#xff1a;可以少传一个/多个参数给函数&…

归并排序和分治

归并排序 归并排序是利用归并的思想实现的排序方法&#xff0c;该算法采用经典的分治策略&#xff08;分治法将问题分成一些小的问题然后递归求解&#xff0c;而治的阶段则将分的阶段得到的各答案"修补"在一起&#xff0c;即分而治之)。 分而治之 可以看到这种结构…

前端实现菜单搜索搜索(功能模版)

目录 前言正文 前言 总体界面如下所示&#xff1a; 正文 <template><div class"avue-searchs"click.self"handleEsc"><div class"avue-searchs__title">菜单搜索</div><div class"avue-searchs__content"…

游戏运营分析:如何在新游戏上线初期实现精细化运营?

一、背景介绍 在当今的手游市场中&#xff0c;每一款新游戏的发布都如同踏上一段充满未知与挑战的探险之旅。游戏刚上线时&#xff0c;运营情况往往如同飘摇的小船&#xff0c;随时可能受到风浪的侵袭。此时&#xff0c;如何准确地找到问题所在&#xff0c;为游戏的健康运营和持…

瀚海贫者福,铜子恣意游

上学时打饭追求性价比的习惯一直不改&#xff0c;半个大鱼头三块钱&#xff0c;一份豆腐一块钱&#xff0c;还有一个红烧茄子2块5&#xff0c;再加三毛钱的饭&#xff0c;共6块8毛钱&#xff0c;早晚餐也会有这类性价比高又营养的选择&#xff0c;科大食堂现在越来越人性化&…

蓝桥杯练习——拼出一个未来

选中 index.html 右键启动 Web Server 服务&#xff08;Open with Live Server&#xff09;&#xff0c;让项目运行起来。接着&#xff0c;打开环境右侧的【Web 服务】&#xff0c;就可以在浏览器中看到如下效果&#xff1a; 目标 完善 js/index.js 的 TODO 部分&#xff0c;实…

零基础学会Python

⭐简单说两句⭐ ✨ 正在努力的小新~ &#x1f496; 超级爱分享&#xff0c;分享各种有趣干货&#xff01; &#x1f469;‍&#x1f4bb; 提供&#xff1a;模拟面试 | 简历诊断 | 独家简历模板 &#x1f308; 感谢关注&#xff0c;关注了你就是我的超级粉丝啦&#xff01; &…

C 回调函数的两种使用方法

对回调&#xff08;callback&#xff09;函数的一点粗陋理解&#xff0c;在我小时候&#xff0c;隔壁村有家月饼小作坊&#xff08;只在中秋那段时间手工制作一些月饼出售&#xff0c;后来好像不做了&#xff09;&#xff0c;做出的月饼是那种很传统很经典的款式&#xff0c;里…

电机的工作电流怎么计算?

电机的工作电流计算通常需要考虑多个因素&#xff0c;包括电机的额定功率、工作电压、效率以及负载情况等。以下是一个基本的计算方法&#xff0c;用于估算直流电机或交流电机在特定条件下的工作电流。 了解电机参数 额定功率 (P_rated) 电机的额定功率是指在额定工作条件下&am…

深入C语言:探究static关键字的奥秘

文章目录 一、链接属性二、static变量1、定义静态局部变量2、在函数内部使用静态变量3、函数中静态局部变量与递归 三、static变量与全局变量的区别1、存储期与生命周期2、可见性与作用域3、使用场景4、静态与动态内存分配 注意事项 当用于不同的上下文环境时&#xff0c; sta…

005 高并发内存池_CentralCache设计

​&#x1f308;个人主页&#xff1a;Fan_558 &#x1f525; 系列专栏&#xff1a;高并发内存池 &#x1f339;关注我&#x1f4aa;&#x1f3fb;带你学更多知识 文章目录 前言本文重点一、构建CentralCache结构二、运用慢开始反馈调节算法三、完成向CentralCache中心缓存申请四…

Netty经典32连问

文章目录 1、Netty是什么&#xff0c;它的主要特点是什么&#xff1f;2、Netty 应用场景了解么&#xff1f;3、Netty 核心组件有哪些&#xff1f;分别有什么作用&#xff1f;4、Netty的线程模型是怎样的&#xff1f;如何优化性能&#xff1f;5、EventloopGroup了解么?和 Event…

第十三届蓝桥杯大赛软件赛省赛CC++大学B组

第十三届蓝桥杯大赛软件赛省赛CC 大学 B 组 文章目录 第十三届蓝桥杯大赛软件赛省赛CC 大学 B 组1、九进制转十进制2、顺子日期3、刷题统计4、修建灌木5、x进制减法6、统计子矩阵7、积木画8、扫雷9、李白打酒加强版10、砍竹子 1、九进制转十进制 计算器计算即可。2999292。 2、…

RD55UP06-V 三菱iQ-R系列C语言功能模块

RD55UP06-V 三菱iQ-R系列C语言功能模块 RD55UP06-V用户手册&#xff0c;RD55UP06-V功能&#xff0c;RD55UP06-V系统配置 RD55UP06-V参数规格&#xff1a;10BASE-T/100BASE-TX/1000BASE-T 1通道&#xff1b;字节存储次序格式小端模式; 可使用SD存储卡插槽&#xff1b;工作RAM 1…

路由、插槽

路由 前端路由&#xff1a;Hash地址(url中#后面的部分)与组件之间的对应关系 页面效果&#xff1a;在浏览器中访问不同的Hash地址时&#xff0c;会显示不同的组件 SPA项目(单页面应用程序&#xff0c;就是Vue项目&#xff0c;最后所有模板都展示在一个html上) vue路由(vue-r…

VUE3——生命周期

Vue3.0中可以继续使用Vue2.x中的生命周期钩子&#xff0c;但有有两个被更名&#xff1a; beforeDestroy改名为 beforeUnmountdestroyed改名为 unmounted Vue3.0也提供了 Composition API 形式的生命周期钩子&#xff0c;与Vue2.x中钩子对应关系如下&#xff1a; beforeCreate&g…

3D Gaussian Splatting Linux端部署指南(含Linux可视化)

3D Gaussian Splatting Linux端部署指南 目录 项目地址 部署记录 11. Linux端在线远程可视化训练进程 准备自己的数据 SIBR_remoteGaussian在线远程可视化 补充&#xff1a;sibr_3Dgaussian离线可视化训练好的模型 朋友浩哥说环境是最难配的&#xff0c;配好环境&#x…

Tinymce富文本编辑器二次开发电子病历时解决的bug

前言 本文是在Tinymce富文本编辑器添加自定义toolbar&#xff0c;二级菜单&#xff0c;自定义表单&#xff0c;签名的基础之上进行一些bug记录&#xff0c;功能添加&#xff0c;以及模版的应用和打印 项目描述 建立电子病历模版—录入&#xff08;电子病历模版和电子病历打印…