力扣刷题篇之分治

系列文章目录


目录

系列文章目录

前言

一、分解问题

二、解决子问题

三、合并结果

总结


前言

刷题按照:

[力扣刷题攻略] Re:从零开始的力扣刷题生活 - 力扣(LeetCode)

参考:

「五大常用算法」一文搞懂分治算法 - 知乎 (zhihu.com)

分治算法(divide and conquer)是五大常用算法(分治算法、动态规划算法、贪心算法、回溯法、分治界限法)之一,分治,字面上的解释是“分而治之”,就是把一个复杂的问题分成两个或更多的相同或相似的子问题,再把子问题分成更小的子问题……直到最后子问题可以简单的直接求解,原问题的解即子问题的解的合并。在计算机科学中,分治法就是运用分治思想的一种很重要的算法。分治法是很多高效算法的基础,如排序算法(快速排序,归并排序),傅立叶变换(快速傅立叶变换)等等。


一、分解问题

169. 多数元素 - 力扣(LeetCode)

//方法一:排序取中值
// class Solution {
//     public int majorityElement(int[] nums) {
//         Arrays.sort(nums);
//         return nums[nums.length/2];
//     }
// }

//方法二:投票法,众数的个数大于n/2,顾投票总数大于0
// class Solution {
//     public int majorityElement(int[] nums) {
//         int count = 0;
//         Integer mode = null;

//         for(int num : nums)
//         {
//             if(count == 0)
//             {
//                 mode = num;
//             }
//             count += (num == mode) ? 1 : -1;
//         }
//         return mode;
//     }
// }

//方法三:HashMap,数组元素作为键值对的Key,出现个数作为键值对的Value,存放时出现相同的Key,将对应Value进行加1后放到
//HashMap中,遍历数据完成后返回Value值大于n/2的即可。
// class Solution {
//     public int majorityElement(int[] nums) {
//         Map<Integer, Integer> countMap = new HashMap<> ();
//         for(int num : nums)
//         {
//             if(!countMap.containsKey(num))
//             {
//                 countMap.put(num, 1);
//             }
//             else
//             {
//                 countMap.put(num, countMap.get(num) + 1);
//             }

//             if(countMap.get(num) > nums.length / 2)
//             {
//                 return num;
//             }
//         }
//         return -1;
//     }
// }

// //方法四:回调投票
class Solution {
    public int majorityElement(int[] nums) {
        return moore(0, nums, nums[0]);
    }

    public int moore(int i, int[] nums, int mode){
        int count = 0;
        for(int j = i; j < nums.length; j++){
            if(nums[j] == mode){
                count++;
            }
            else{
                count--;
            }

            if(count < 0){
                return moore(j, nums, nums[j]);
            }
        }
        return mode;
    }
}

4. 寻找两个正序数组的中位数 - 力扣(LeetCode)

class Solution {
    public double findMedianSortedArrays(int[] nums1, int[] nums2) {
        int totalLength = nums1.length + nums2.length;
        int halfLength = totalLength / 2;

        if (totalLength % 2 == 0) {
            // 如果总长度是偶数,中位数是左侧部分的最大值和右侧部分的最小值之和的一半
            double leftMedian = findKthElement(nums1, 0, nums2, 0, halfLength);
            double rightMedian = findKthElement(nums1, 0, nums2, 0, halfLength + 1);
            return (leftMedian + rightMedian) / 2.0;
        } else {
            // 如果总长度是奇数,中位数就是右侧部分的最小值
            return findKthElement(nums1, 0, nums2, 0, halfLength + 1);
        }
    }

    private double findKthElement(int[] nums1, int start1, int[] nums2, int start2, int k) {
        if (start1 == nums1.length) {
            // 如果 nums1 部分已经为空,则直接返回 nums2 部分的第 k 个元素
            return nums2[start2 + k - 1];
        }
        if (start2 == nums2.length) {
            // 如果 nums2 部分已经为空,则直接返回 nums1 部分的第 k 个元素
            return nums1[start1 + k - 1];
        }
        if (k == 1) {
            // 如果 k 等于 1,则直接返回两个数组当前部分的最小值
            return Math.min(nums1[start1], nums2[start2]);
        }

        // 在两个数组中寻找第 k/2 个元素,并更新两个数组的起始位置
        int mid1 = start1 + k / 2 - 1 < nums1.length ? nums1[start1 + k / 2 - 1] : Integer.MAX_VALUE;
        int mid2 = start2 + k / 2 - 1 < nums2.length ? nums2[start2 + k / 2 - 1] : Integer.MAX_VALUE;

        if (mid1 < mid2) {
            // 如果 nums1 的中间元素小于 nums2 的中间元素,则舍弃 nums1 的左侧部分
            return findKthElement(nums1, start1 + k / 2, nums2, start2, k - k / 2);
        } else {
            // 如果 nums1 的中间元素大于等于 nums2 的中间元素,则舍弃 nums2 的左侧部分
            return findKthElement(nums1, start1, nums2, start2 + k / 2, k - k / 2);
        }
    }
}

543. 二叉树的直径 - 力扣(LeetCode)

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
class Solution {
    int max = 0;
    public int diameterOfBinaryTree(TreeNode root) {
        if (root == null) {
            return 0;
        }
        dfs(root);
        return max;
    }
    
    private int dfs(TreeNode root) {
        if (root.left == null && root.right == null) {
            return 0;
        }
        int leftSize = root.left == null? 0: dfs(root.left) + 1;
        int rightSize = root.right == null? 0: dfs(root.right) + 1;
        max = Math.max(max, leftSize + rightSize);
        return Math.max(leftSize, rightSize);
    }  
}

二、解决子问题

69. x 的平方根 - 力扣(LeetCode)

牛顿迭代法:Integer square root - Wikipedia

class Solution {
    public int mySqrt(int x) {
        if (x == 0) {
            return 0;
        }

        double x0 = x; // 初始猜测值
        double x1 = 0.5 * (x0 + x / x0); // 使用牛顿迭代法更新猜测值

        // 迭代直到猜测值不再变化
        while (Math.abs(x1 - x0) >= 1) {
            x0 = x1;
            x1 = 0.5 * (x0 + x / x0);
        }

        return (int) x1; // 将最终结果转换为整数并返回
    }
}

一个特殊的方法来计算平方根,即通过取指数和对数的方式。实际上,这是一种常见的近似计算方法。它的基本思想是,计算 x 的平方根,可以转换为计算 e^(0.5 * ln(x))。在这里,Math.exp(0.5 * Math.log(x)) 计算的是 e^(0.5 * ln(x))。 

class Solution {
    public int mySqrt(int x) {
        if (x == 0) {
            return 0;
        }
        int ans = (int) Math.exp(0.5 * Math.log(x));
        return (long) (ans + 1) * (ans + 1) <= x ? ans + 1 : ans;
    }
}

 53. 最大子数组和 - 力扣(LeetCode)

class Solution {
    public int maxSubArray(int[] nums) {
        int ans = Integer.MIN_VALUE;
        int count = 0;
        for (int i=0; i<nums.length; i++) {
            count = Math.max(count + nums[i], nums[i]);
            ans = Math.max(ans, count);
        }
        return ans;
    }
}

34. 在排序数组中查找元素的第一个和最后一个位置 - 力扣(LeetCode)

class Solution {
    public int[] searchRange(int[] nums, int target) {
        int[] res = {-1, -1};

        // 寻找第一个出现的位置
        int left = 0, right = nums.length - 1;
        while (left <= right) {
            int mid = left + (right - left) / 2;
            if (nums[mid] == target) {
                res[0] = mid;
                right = mid - 1; // 继续在左半边搜索
            } else if (nums[mid] < target) {
                left = mid + 1;
            } else {
                right = mid - 1;
            }
        }

        // 如果未找到目标值,直接返回
        if (res[0] == -1) {
            return res;
        }

        // 寻找最后一个出现的位置
        left = res[0]; // 左边界从第一次找到的位置开始
        right = nums.length - 1;
        while (left <= right) {
            int mid = left + (right - left) / 2;
            if (nums[mid] == target) {
                res[1] = mid;
                left = mid + 1; // 继续在右半边搜索
            } else if (nums[mid] < target) {
                left = mid + 1;
            } else {
                right = mid - 1;
            }
        }

        return res;
    }
}

三、合并结果

23. 合并 K 个升序链表 - 力扣(LeetCode)

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
   // 合并两个有序链表
    public ListNode mergeKLists(ListNode[] lists) {
        if (lists.length == 0) {
            return null;
        }
        return split(lists, 0, lists.length - 1);
    }

    public ListNode split(ListNode[] lists, int i, int j) {
//        System.out.println(i + " " + j);
        if (j == i) {
            return lists[i];
        }
        int m = (i + j) >>> 1;
        return mergeTwoLists(
                split(lists, i, m),
                split(lists, m + 1, j)
        );
    }

    public ListNode mergeTwoLists(ListNode p1, ListNode p2) {
        if (p2 == null || p1 == null) {
            return p2 == null ? p1 : p2;
        }
        if (p1.val < p2.val) {
            p1.next = mergeTwoLists(p1.next, p2);
            return p1;
        } else {
            p2.next = mergeTwoLists(p1, p2.next);
            return p2;
        }
    }
}

1277. 统计全为 1 的正方形子矩阵 - 力扣(LeetCode)

动态规划 

    class Solution {
        public int countSquares(int[][] matrix) {
            // 动态规划, 二维数组dp[i][j]表示以i,j为右下角的最大的全1正方形的边长
            // if matrix[i][j] == '1' -> dp[i][j] = Min{dp[i - 1][j - 1], dp[i - 1][j], dp[i][j - 1]} + 1
            int m = matrix.length;
            int n = matrix[0].length;
            int[][] dp = new int[m][n];
            // 初始化边界
            int result = 0;
            for (int i = 0; i < m; i++) {
                if (matrix[i][0] == 1) {
                    dp[i][0] = 1;
                }
            }
            for (int i = 0; i < n; i++) {
                if (matrix[0][i] == 1) {
                    dp[0][i] = 1;
                }
            }
            // 自底向上
            for (int i = 1; i < m; i++) {
                for (int j = 1; j < n; j++) {
                    if (matrix[i][j] == 0) {
                        dp[i][j] = 0;
                    } else {
                        dp[i][j] = Math.min(dp[i - 1][j - 1], Math.min(dp[i - 1][j], dp[i][j - 1])) + 1;
                    }
                }
            }
            // 遍历dp
            for (int i = 0; i < m; i++) {
                for (int j = 0; j < n; j++) {
                    result += dp[i][j];
                }
            }
            return result;
        }

    }

 


总结

分治法很重要,然后我发现做题勾勾画画还挺有用的,希望多敲多做,慢慢来吧。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

爬虫学习 异步爬虫(五)

多线程 多进程 协程 进程 运行中的程序 线程 被CPU调度的执行过程,操作系统 运算调度的min单位 在进程之中,进程中实际运作单位 from threading import Thread#创建任务 def func(name):for i in range(100):print(name,i)if __name__ __main__:#创建线程t1 Thread(target …

异步操作的方法

在高级语言中已经有了异步的原语言&#xff0c;而在C 中的最好的方式就是 libevent 的方式,我这还是相当认同的&#xff0c;高级语言就不需要在苦哈哈的&#xff0c;事件转圈了&#xff0c;但是原理还是以事件为基础的 一句话就是在一个循环中等着他执行完,这个循环中有很多其他…

CodeMeter软件保护及授权管理解决方案(二)

客户端管理工具 CodeMeter Runtime是CodeMeter解决方案中的重要组成部分&#xff0c;其为独立软件包&#xff0c;开发者需要把CodeMeter Runtime和加密后的软件一起发布。CodeMeter Runtim包括以下组件用于实现授权的使用&#xff1a; CodeMeter License Server授权服务器 Co…

Leetcode(面试题 08.01.)三步问题

文章目录 前言一、题目分析二、算法原理1.状态表示2.状态转移方程3.初始化4.填表顺序5.返回值是什么 三、代码实现总结 前言 在本文章中&#xff0c;我们将要详细介绍一下Leetcode(面试题 08.01.)三步问题相关的内容 一、题目分析 1.小孩可以上一阶&#xff0c;两阶&#xff…

2948. 交换得到字典序最小的数组 (分组排序)

Problem: 2948. 交换得到字典序最小的数组 文章目录 题目思路Code 题目 给你一个下标从 0 开始的 正整数 数组 nums 和一个 正整数 limit 。 在一次操作中&#xff0c;你可以选择任意两个下标 i 和 j&#xff0c;如果 满足 |nums[i] - nums[j]| < limit &#xff0c;则交换…

Python之数据可视化

文章目录 一、1、matplotlib简单应用1.1、绘制带有中文标签和图例的图1.2、 绘制散点图1.3、绘制饼状图1.4、多个图形一起显示 一、 1、matplotlib简单应用 matplotlib模块依赖于numpy模块和tkinter模块&#xff0c;可以绘制多种形式的图形&#xff0c;包括线图、直方图、饼状…

05_MySQL主从复制架构

任务背景 ##一、真实案例 某同学刚入职公司&#xff0c;在熟悉公司业务环境的时候&#xff0c;发现他们的数据库架构是一主两从&#xff0c;但是两台从数据库和主库不同步。询问得知&#xff0c;已经好几个月不同步了&#xff0c;但是每天会全库备份主服务器上的数据到从服务…

一文详解Python中常用数据类型

文章目录 Python 中常用的数据类型包括&#xff1a;Python 中布尔类型(bool)Python 中的数字类型概述Pyhon中的字符串概述Python 中的List概述Python 中的元组类型(tuple)Python中的字典&#xff08;Dictionary&#xff09;Python中的集合&#xff08;Set&#xff09;Python中的…

Python---练习:求某同学成绩的总分及平均分

需求&#xff1a; 已知某同学的语文(70)、数学(90) 、英语(80)、历史(75)、地理(85)五门课的成绩,编程求该同学的总分以及平均分。 思考&#xff1a; 要求是算总分和平均分&#xff0c;先看总分&#xff0c;已经知道了各科成绩&#xff0c;那么可以用把成绩赋值给每个学科的…

使用Postman创建Mock Server

这篇文章将教会大家如何利用 Postman&#xff0c;通过 Mock 的方式测试我们的 API。 什么是 Mock Mock 是一项特殊的测试技巧&#xff0c;可以在没有依赖项的情况下进行单元测试。通常情况下&#xff0c;Mock 与其他方法的主要区别就是&#xff0c;用于取代代码依赖项的模拟对…

Linux下Docker 离线安装详细步骤,亲测成功

1.离线原因&#xff1a;公司新创不能使用开元linux&#xff0c;使用了一个变种centOS&#xff0c;致使yum被禁 2.步骤&#xff1a; 2.1 下载docker tar包&#xff0c;下载地址&#xff1a;Index of linux/https://download.docker.com/linux/ 2.2 新建自己的软件目录&am…

IELTS学习笔记_grammar_新东方

参考&#xff1a; 新东方 田静 语法 目录&#xff1a; 导学简单句… x.1 导学 学语法以应用为主。 基础为&#xff1a;单词&#xff0c;语法 进阶为&#xff1a;听说读写译&#xff0c;只考听说读写。 words -> chunks -> sentences, chunks&#xff08;语块的重要…

嵌入式设备与PC上位机通信协议设计的几点原则

嵌入式设备在运行中需要设置参数&#xff0c;这个工作经常由PC机来实现&#xff0c;需要为双方通信设计协议&#xff0c;有代表性协议是如下三种&#xff1a; 从上表可以看到&#xff0c;一般嵌入式设备内存和运算性能都有限&#xff0c;因此固定二进制是首选通信协议。 一&am…

使用 Docker 安装和配置 MySQL 数据库简介

目录 一、使用镜像安装 1、查询镜像 2、拉取镜像 3、查看本地镜像 4、启动docker镜像 二、使用Docker Compose安装 1、安装Docker和Docker Compose 2、创建Docker Compose文件&#xff1a; 3、启动MySQL容器 4、验证MySQL容器是否正常运行 5、连接到MySQL容器 6、停止…

智能优化算法应用:基于水循环算法无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用&#xff1a;基于水循环算法无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用&#xff1a;基于水循环算法无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.水循环算法4.实验参数设定5.算法结果6.参考文献7.…

Error running OrderServiceBoot. Command line is too long.

微服务启动不成功&#xff0c;报Error running OrderServiceBoot. Command line is too long. Shorten the command line via JAR manifest or via a classpath file and rerun. 解决&#xff1a; 方法一&#xff1a; 右上角启动小三角 -->Edit configuration–>-右侧…

【Python】基础练习题_组合数据类型_2

dictMenu f’卡布奇洛’:32,‘摩卡’:30,‘抹茶蛋糕’:28,‘布朗尼’:26}&#xff0c; dictMenu 中存放了你的双人下午套餐&#xff08;包括咖啡2份和点心2份)的价格,请编写程序,让Python帮忙计算并输出消费总额。 dictMenu {卡布奇洛: 32, 摩卡: 30, 抹茶蛋糕: 28, 布朗尼: 2…

leetcode 287. 寻找重复数

2023.11.29 本题比较朴素得一个思路是利用map集合的key存储nums中的值&#xff0c;value存储对应值出现的次数&#xff0c;然后再遍历这个map集合的value&#xff0c;如果这个value大于1&#xff0c;说明对应的key出现的次数超过了1次&#xff0c;并且题目说这个key唯一&#x…

[个人笔记] vCenter6.7使用自建SSL证书

SSL - 运维篇 第三章 vCenter6.7使用自建SSL证书 SSL - 运维篇系列文章回顾vCenter6.7使用自建SSL证书vCenter 6.7 上传文件到ShellvCenter 6.7 Shell 替换SSL证书全流程测试&验证 参考链接 系列文章回顾 第二章 FortiGate防火墙使用自建SSL证书 vCenter6.7使用自建SSL证书…

LeetCode(41)单词规律【哈希表】【简单】

目录 1.题目2.答案3.提交结果截图 链接&#xff1a; 单词规律 1.题目 给定一种规律 pattern 和一个字符串 s &#xff0c;判断 s 是否遵循相同的规律。 这里的 遵循 指完全匹配&#xff0c;例如&#xff0c; pattern 里的每个字母和字符串 s 中的每个非空单词之间存在着双向连…