当前位置: 首页 > news >正文

hot100-栈 二分

155. 最小栈

解法一、栈与数组

实际上也可以用辅助栈

class MinStack {
    private Deque<int[]> st = new LinkedList<>();

    public MinStack() {
        st.push(new int[]{0,Integer.MAX_VALUE});
    }

    public void push(int val) {
        st.push(new int[]{val,Math.min(val,st.peek()[1])});
    }

    public void pop() {
        st.pop();
    }

    public int top() {
        return st.peek()[0];
    }

    public int getMin() {
        return st.peek()[1];
    }
}


739. 每日温度

解法一、单调栈

class Solution {
    public int[] dailyTemperatures(int[] temperatures) {
        Deque<Integer> st = new LinkedList<>();
        int n = temperatures.length;
        int[] res = new int[n];
        for(int i = 0;i<n;i++){
            while(!st.isEmpty() && temperatures[st.peek()] < temperatures[i]){
                res[st.peek()] = i - st.pop();
            }//要不然空要不然最后一个大等
            st.push(i);
        }
        return res;
    }
}

二分查找


74. 搜索二维矩阵

l指向的是首个元素大于target的一行的前一行。所以要判断首行的首个元素是不是大于target,若是,则l指向-1,再往后走会爆数组下标。

class Solution {
    public boolean searchMatrix(int[][] matrix, int target) {
        int n = matrix.length,m = matrix[0].length;
        int l = -1,r = n;
        if(matrix[0][0] > target)return false;
        while(l + 1 < r){
            int mid = l + (r - l)/2;
            if(matrix[mid][0] == target){
                return true;
            }else if(matrix[mid][0] < target){
                l = mid;
            }else{
                r = mid;
            }
        }
        int t = l;
        l = -1;
        r = m;
        while(l + 1 < r){
            int mid = l + (r - l)/2;
            if(matrix[t][mid] == target){
                return true;
            }else if(matrix[t][mid] < target){
                l = mid;
            }else{
                r = mid;
            }
        }
        return l == r;
    }
}

 解法一、二分

class Solution {
    public boolean searchMatrix(int[][] matrix, int target) {
        int n = matrix.length,m = matrix[0].length;
        int l = -1,r = n;
        if(matrix[0][0] > target)return false;
        while(l + 1 < r){
            int mid = l + (r - l)/2;
            if(matrix[mid][0] == target){
                return true;
            }else if(matrix[mid][0] < target){
                l = mid;
            }else{
                r = mid;
            }
        }
        int t = l;
        l = -1;
        r = m;
        while(l + 1 < r){
            int mid = l + (r - l)/2;
            if(matrix[t][mid] == target){
                return true;
            }else if(matrix[t][mid] < target){
                l = mid;
            }else{
                r = mid;
            }
        }
        return l == r;
    }
}

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

解法一、二分

rR记录第一次的r,在第一次中,l是最后一个小于target的数,r是第一个target(如果target存在)。在第二次中,l是最后一个target(如果target存在),r是target右侧第一个数。

如果第一次的r比第二次的l大,则target不存在。

class Solution {
    public int[] searchRange(int[] nums, int target) {
        //0 1 2 4 4 6 0
        int n = nums.length,l = -1,r = n;
        while(l + 1 < r){
            int mid = l + (r - l) / 2;
            if(nums[mid] < target){
                l = mid;
            }else{
                r = mid;
            }
        }
        // 5 7
        int rR = r;
        l = -1;
        r = n;
        while(l + 1 < r){
            int mid = l + (r - l) / 2;
            if(nums[mid] <= target){
                l = mid;
            }else{
                r = mid;
            }
        }
        return rR > l ? new int[]{-1,-1}: new int[]{rR,l};
    }
}

 
33. 搜索旋转排序数组

解法一、二分

双次二分,第一次找到是分界点(如 3456012) l指向6 r指向0

第二次根据和第一个点的大小关系进行分区段二分

class Solution {
    public int search(int[] nums, int target) {
        //判断是否大于nums[0],
        int n = nums.length,l = -1,r = n;
        if(n == 1) return nums[0] == target ? 0 : -1;
        while(l + 1 < r){
            int mid = l + (r - l)/2;
            if(nums[mid] >= nums[0]){
                l = mid;
            }else{
                r = mid;
            }
        }
        //理想情况下 l是左侧最后 r是右侧第一
        if(target >= nums[0]){
            l = -1;
        }else{
            r = n;
        }
        while(l + 1 < r){
            int mid = l + (r - l)/2;
            if(nums[mid] == target){
                return mid;
            }else if(nums[mid] < target){
                l = mid;
            }else {
                r = mid;
            }
        }
        return -1;
    }
}

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

解法一、二分

class Solution {
    public int findMin(int[] nums) {
        //判断是否大于nums[0],
        int n = nums.length,l = -1,r = n;
        if(n == 1) return nums[0];
        while(l + 1 < r){
            int mid = l + (r - l)/2;
            if(nums[mid] >= nums[0]){
                l = mid;
            }else{
                r = mid;
            }
        }
        return r != n ? nums[r] : nums[0];
    }
}


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

解法一、 二分

大体上分两部分。检索较短的数组,确保效率较高。i是nums1里分割线左侧的点,j是nums2里分割线左侧的点。

数组分割要求:①两侧加起来为(n+m+1)/2 ②a数组最大<b数组最小

因为nums1数组是更小的那个 所以无论如何nums2里一定会被分一部分

class Solution {
    public double findMedianSortedArrays(int[] nums1, int[] nums2) {
        if(nums1.length > nums2.length){
            int[] temp = nums2;
            nums2 = nums1;
            nums1 = temp;
        }
        int m = nums1.length,n = nums2.length,l = -1,r = m;
        //变小
        while(l + 1 < r){
            //如果
            int i = l + (r - l)/2;
            int j = (m + n + 1)/2 - 2 - i;
            if(nums1[i] <= nums2[j+1]){//右移
                l = i;
            }else{
                r = i;
            }
        }
        int i = l;
        int j = (m+n+1)/2 - 2 - i;
        int ai = i < 0 ? Integer.MIN_VALUE : nums1[i];
        int bj = j < 0 ? Integer.MIN_VALUE : nums2[j];
        int ai1 = i+1 >= m ? Integer.MAX_VALUE : nums1[i+1];
        int bj1 = j+1 >= n ? Integer.MAX_VALUE : nums2[j+1];
        int maxA = Math.max(ai,bj); 
        int minB = Math.min(ai1,bj1);
        return (m+n)%2==0 ? (double)(maxA+minB)/2 : (double)maxA;
    }
}

215. 数组中的第K个最大元素

解法一、堆排序

class Solution {
    private void swap(int[] nums,int i,int j){
        int temp = nums[i];
        nums[i] = nums[j];
        nums[j] = temp;
    }
    public void heapify(int[] nums, int n,int i) {
        int node = i;
        int l = i * 2 + 1;
        int r = i * 2 + 2;
        if(l < n && nums[l] > nums[node]){
            node = l;
        }
        if(r < n && nums[r] > nums[node]){
            node = r;
        }
        if(node != i){
            swap(nums,i,node);
            heapify(nums,n,node);
        }
    }
    public int findKthLargest(int[] nums, int k) {
        int n = nums.length;
        for(int i = n/2-1;i >= 0;i--){
            heapify(nums,n,i);
        }
        for(int i = n-1;i >= n-k;--i){
            swap(nums,0,i);
            heapify(nums,i,0);
        }
        return nums[n-k];
    }
}

 
​​​​​​347. 前 K 个高频元素

解法一、堆排序

class Solution {
    private Map<Integer,Integer> hm = new HashMap<>();
    public int[] topKFrequent(int[] nums, int k) {
        int n = nums.length;
        for(int i = 0;i < n;i++){
            hm.put(nums[i],hm.getOrDefault(nums[i],0)+1);
        }
        PriorityQueue<int[]> queue = new PriorityQueue<int[]>(new Comparator<int[]>() {
            @Override
            public int compare(int[] o1, int[] o2) {
                return o1[1] - o2[1];
            }
        });
        for(Map.Entry<Integer,Integer> h : hm.entrySet()){
            int num = h.getKey(),count = h.getValue();
            if(queue.size() == k){
                if(queue.peek()[1] < count){
                    queue.poll();
                    queue.offer(new int[]{num,count});
                }
            }else{
                queue.offer(new int[]{num,count});
            }
        }
        int[] res = new int[k];
        for(int i = k-1;i >=0;i--){
            res[i] = queue.poll()[0];
        }
        return res;
    }
}

解法二、自建

class Solution {

 Map<Integer,Integer> map;
    public int[] topKFrequent(int[] nums, int k) {
        int[] ans = new int[k];
         map = new HashMap<>();
        for (int num : nums) {
            map.put(num,map.getOrDefault(num,0)+1);
        }
        int[] arr= new int[map.size()];
        int i=0;
        for (Integer num : map.keySet()) {
            arr[i++] = num;
        }

        //建立小根堆
        buildMinHead(arr,k);
        for (int j = k; j < arr.length; j++) {
            if(map.get(arr[j]) > map.get(arr[0])){
                swap(arr,j,0);
                minHeap(arr,0,k);
            }
        }
        ans = Arrays.copyOf(arr,k);
        return ans;
    }

    private void buildMinHead(int[] arr, int k) {
        for (int i = k/2; i >=0 ; i--) {
            minHeap(arr,i,k);
        }
    }

    private void minHeap(int[] arr, int i, int heapSize) {
        int l = i * 2+1;
        int r = i * 2+2;
        int min = i;
        if(l < heapSize && map.get(arr[l]) < map.get(arr[min])) min = l;
        if(r < heapSize && map.get(arr[r]) < map.get(arr[min])) min = r;
        if(min != i){
            swap(arr,i,min);
            minHeap(arr,min,heapSize);
        }
    }
    public void swap(int[] arr,int i,int j){
        int temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
    }

    // public int[] topKFrequent(int[] nums, int k) {
    //      int[] ans = new int[k];
    //     Map<Integer,Integer> map = new HashMap<>();
    //     for (int num : nums) {
    //         map.put(num,map.getOrDefault(num,0)+1);
    //     }
    //     PriorityQueue<int[]> pq = new PriorityQueue<>((o1, o2) ->  o2[1]-o1[1]);
    //     for (Map.Entry<Integer, Integer> entry : map.entrySet()) {
    //         pq.add(new int[]{entry.getKey(),entry.getValue()});
    //     }

    //     for (int i = 0; i < k; i++) {
    //         ans[i] = pq.poll()[0];
    //     }
    //     return ans;
    // }
}


295. 数据流的中位数

解法一、堆

较慢写法

class MedianFinder {
    private PriorityQueue<Integer> left = new PriorityQueue<>((a,b) -> b - a);//大根堆
        private PriorityQueue<Integer> right = new PriorityQueue<>();//小根堆
    public MedianFinder() {
        
    }
    
    public void addNum(int num) {
        if(left.size() == right.size()){
            right.offer(num);
            left.offer(right.poll());
        }else{
            left.offer(num);
            right.offer(left.poll());
        }
    }
    
    public double findMedian() {
        if(left.size() > right.size()){
            return left.peek();
        }
        return (left.peek() + right.peek())/2.0;
    }
}

 较快写法

class MedianFinder {
    private PriorityQueue<Integer> minQue;
    private PriorityQueue<Integer> maxQue;
    public MedianFinder() {
        minQue = new PriorityQueue<>((o1,o2)->o1-o2);
        maxQue = new PriorityQueue<>((o1,o2)->o2-o1);
    }
    
    public void addNum(int num) {
        if(minQue.isEmpty()||num>=minQue.peek()){
            minQue.offer(num);
        }else{
            maxQue.offer(num);
        }
        if(minQue.size()>maxQue.size()+1){
            maxQue.offer(minQue.poll());
        }else if(maxQue.size()>minQue.size()){
            minQue.offer(maxQue.poll());
        }
    }
    
    public double findMedian() {
        if(minQue.size()==maxQue.size()){
            return (minQue.peek()+maxQue.peek())/2.0;
        }else{
            return minQue.peek();
        }
    }
}

​​​​​​​


①对于Map 通过该种方式进行遍历

for(Map.Entry<Integer,Integer> h : hm.entrySet()) {
    int num = h.getKey(), count = h.getValue();
}

② 使用PriorityQueue表示堆排调库

相关文章:

  • 【我的 PWN 学习手札】IO_FILE 之 利用IO_validate_vtable劫持程序流
  • 【构建工具】Gradle 8中Android BuildConfig的变化与开启方法
  • WSL2下,向github进行push时出现timeout的问题
  • Web漏洞——命令注入漏洞学习
  • 【弹性计算】Guest OS
  • 内存资源分配
  • 视频推拉流EasyDSS直播点播平台授权激活码无效,报错400的原因是什么?
  • java后端开发day21--面向对象进阶(二)--继承进阶
  • Week 2 - Algorithm efficiency + Searching/Sorting
  • 浅谈HTTP及HTTPS协议
  • 亚马逊详情接口:开发、应用与实战指南
  • osgEarth安装总结
  • 洛谷 B2006:地球人口承载力估计 ← float 类型
  • 基于开源鸿蒙(OpenHarmony)的【智能家居综合应用】系统
  • 蓝桥杯---快速排序(leetcode第159题)最小的k个元素(剑指offer原题)
  • react 新手入门指南,常用命令
  • 【Uniapp-Vue3】开发userStore用户所需的相关操作
  • 【Python爬虫(85)】联邦学习:爬虫数据协作的隐私保护新范式
  • 本地部署 deepseek-r1 1.5B方法-ubuntu20.04 python3.10 pycharm虚拟环境
  • QEMU源码全解析 —— 内存虚拟化(21)
  • 解放日报:浦东夯实“热带雨林”式科创生态
  • 中国强镇密码丨洪泽湖畔的蒋坝,如何打破古镇刻板印象
  • 新开发银行如何开启第二个“金色十年”?
  • “光荣之城”2025上海红色文化季启动,红色主题市集亮相
  • 2025上海体育消费节启动,多形式联动打造体育消费盛宴
  • 俄罗斯总统普京:5月8日零时至11日零时实施停火