Java每日精进·45天挑战·Day19
第一部分:移除数字以形成最小数的贪心算法实现
在编程的世界里,我们经常遇到需要对字符串表示的数字进行操作的问题。今天,我们要深入探讨一个具体的挑战:给定一个以字符串形式表示的非负整数 num
和一个整数 k
,我们的任务是移除 k
位数字,以使得剩下的数字尽可能小。最终,我们需要返回这个最小的数字(仍然以字符串形式)。
问题背景
这个问题看似简单,实则充满了挑战。我们需要仔细思考如何高效地移除数字,以确保剩下的数字最小。为了更好地理解这个问题,让我们先来看几个示例:
-
输入:
num = "1432219"
,k = 3
输出:"1219"
解释:移除数字 4、3 和 2 后,我们得到新的最小数字 "1219"。 -
输入:
num = "10200"
,k = 1
输出:"200"
解释:移除首位的 1 后,剩下的数字为 "200"。注意,输出不能有任何前导零,除非整个数字就是零。 -
输入:
num = "10"
,k = 2
输出:"0"
解释:移除所有数字后,结果为空,因此返回 "0"。
贪心算法思路
为了解决这个问题,我们可以采用贪心算法。贪心算法在每一步选择中都采取最好或最优(即最有利)的选择,从而希望能够导致结果是全局最好或最优的算法。
在这个问题中,我们的每一步选择是:尽可能让高位数字小。具体思路如下:
-
使用一个栈来维护当前构建的最小数字。栈的特点是后进先出(LIFO),非常适合用于这种需要“回溯”的场景。
-
遍历输入字符串的每一个字符:
- 如果栈不为空,当前字符比栈顶字符小,且还有移除次数
k
大于 0,那么我们可以弹出栈顶字符,并将k
减 1。这样做的目的是确保高位数字尽可能小。 - 将当前字符压入栈中。
- 如果栈不为空,当前字符比栈顶字符小,且还有移除次数
-
遍历结束后,如果移除次数
k
仍然大于 0,说明还需要从栈顶继续移除字符,直到k
为 0。 -
构建结果字符串并去除前导零。将栈中的字符依次弹出并拼接成字符串。注意要去除前导零,除非整个数字就是零。
-
处理边界情况。如果最终结果为空字符串,则返回 "0"。
Java 实现
下面,我们将上述思路转化为 Java 代码:
import java.util.Stack;public class RemoveKDigitsBlog {public String removeKDigits(String num, int k) {Stack<Character> stack = new Stack<>();// 遍历输入字符串的每一个字符for (char digit : num.toCharArray()) {// 如果栈不为空,当前字符比栈顶字符小,且还有移除次数 k 大于 0while (!stack.isEmpty() && stack.peek() > digit && k > 0) {stack.pop(); // 弹出栈顶字符k--; // 移除次数减 1}stack.push(digit); // 将当前字符压入栈中}// 如果还有剩余的 k 需要移除,继续从栈顶移除while (k > 0) {stack.pop();k--;}// 构建结果字符串,并去除前导零StringBuilder result = new StringBuilder();while (!stack.isEmpty()) {char digit = stack.pop();if (!(result.length() == 0 && digit == '0')) {result.insert(0, digit);}}// 如果结果为空,则返回 "0"return result.length() == 0 ? "0" : result.toString();}// 为了方便测试,我们在这里添加了一个 main 方法public static void main(String[] args) {RemoveKDigitsBlog solution = new RemoveKDigitsBlog();System.out.println(solution.removeKDigits("1432219", 3)); // 输出 "1219"System.out.println(solution.removeKDigits("10200", 1)); // 输出 "200"System.out.println(solution.removeKDigits("10", 2)); // 输出 "0"// 可以添加更多测试用例来验证算法的正确性}
}
总结
通过贪心算法,我们能够高效地解决这个问题。该算法的时间复杂度是 O(n),其中 n 是输入字符串的长度。这个算法不仅简单易懂,而且在实际应用中表现良好。
希望这篇博客能够帮助你更好地理解这个问题及其解决方案!如果你有任何疑问或建议,请随时在评论区留言。编程的世界充满了无限可能,让我们一起探索、学习和成长!
第二部分:最大和的连续子数组--动态规划与分治法的探索
在算法的世界里,寻找最大和的连续子数组是一个经典的问题,它有多种解法,每种解法都有其独特的魅力和应用场景。今天,我们将深入探讨两种解法:动态规划和分治法,并通过Java代码实现它们。
问题背景
给定一个整数数组 nums
,我们需要找到一个具有最大和的连续子数组(子数组至少包含一个元素),并返回其最大和。连续子数组是数组中的一个连续部分。
动态规划解法
动态规划是一种通过将问题分解为子问题来求解的方法。在这个问题中,我们可以定义一个数组 dp
,其中 dp[i]
表示以 nums[i]
结尾的连续子数组的最大和。状态转移方程为:
dp[i] = max(nums[i], dp[i-1] + nums[i])
这意味着,对于每个元素 nums[i]
,我们要么选择它作为一个新的子数组的起点(即 nums[i]
本身),要么将它加到之前的子数组上(即 dp[i-1] + nums[i]
)。我们取这两种选择中的较大值作为 dp[i]
的值。
最终,我们遍历 dp
数组,找到其中的最大值,即为所求的最大和的连续子数组的和。
Java 实现(动态规划)
public class MaxSubArraySum {public int maxSubArray(int[] nums) {int n = nums.length;int[] dp = new int[n];dp[0] = nums[0];int maxSum = dp[0];for (int i = 1; i < n; i++) {dp[i] = Math.max(nums[i], dp[i - 1] + nums[i]);maxSum = Math.max(maxSum, dp[i]);}return maxSum;}public static void main(String[] args) {MaxSubArraySum solution = new MaxSubArraySum();int[] nums1 = {-2, 1, -3, 4, -1, 2, 1, -5, 4};System.out.println(solution.maxSubArray(nums1)); // 输出 6int[] nums2 = {1};System.out.println(solution.maxSubArray(nums2)); // 输出 1int[] nums3 = {5, 4, -1, 7, 8};System.out.println(solution.maxSubArray(nums3)); // 输出 23}
}
分治法解法
分治法是一种将问题递归地分解为更小的问题,然后合并这些更小的问题的解决方案来得到原问题的解决方案的方法。在这个问题中,我们可以将数组 nums
分为左右两部分,然后分别求解左右两部分的最大和的连续子数组。同时,我们还需要考虑跨越左右两部分的子数组,即最大和的连续子数组可能从左边开始,穿过中间点,然后结束在右边。
对于跨越左右两部分的子数组,我们可以通过在左边部分找到从右往左的最大和的子数组,在右边部分找到从左往右的最大和的子数组,然后将它们相加得到跨越部分的最大和。最后,我们将左右两部分的最大和以及跨越部分的最大和进行比较,取其中的最大值作为当前问题的解。
Java 实现(分治法)
public class MaxSubArraySumDivideAndConquer {public int maxSubArray(int[] nums) {return maxSubArrayHelper(nums, 0, nums.length - 1);}private int maxSubArrayHelper(int[] nums, int left, int right) {if (left == right) {return nums[left];}int mid = left + (right - left) / 2;int leftSum = maxSubArrayHelper(nums, left, mid);int rightSum = maxSubArrayHelper(nums, mid + 1, right);int crossSum = findMaxCrossingSubarray(nums, left, mid, right);return Math.max(Math.max(leftSum, rightSum), crossSum);}private int findMaxCrossingSubarray(int[] nums, int left, int mid, int right) {int leftSum = Integer.MIN_VALUE;int sum = 0;for (int i = mid; i >= left; i--) {sum += nums[i];leftSum = Math.max(leftSum, sum);}int rightSum = Integer.MIN_VALUE;sum = 0;for (int i = mid + 1; i <= right; i++) {sum += nums[i];rightSum = Math.max(rightSum, sum);}return leftSum + rightSum;}public static void main(String[] args) {MaxSubArraySumDivideAndConquer solution = new MaxSubArraySumDivideAndConquer();int[] nums1 = {-2, 1, -3, 4, -1, 2, 1, -5, 4};System.out.println(solution.maxSubArray(nums1)); // 输出 6int[] nums2 = {1};System.out.println(solution.maxSubArray(nums2)); // 输出 1int[] nums3 = {5, 4, -1, 7, 8};System.out.println(solution.maxSubArray(nums3)); // 输出 23}
}
总结
通过动态规划和分治法,我们能够高效地解决寻找最大和的连续子数组的问题。动态规划通过记录以当前元素结尾的子数组的最大和来逐步构建解决方案,而分治法则通过递归地将问题分解为更小的问题来求解。这两种方法都有其独特的优势和适用场景,我们可以根据具体问题的规模和特点来选择合适的方法。
希望这篇博客能够帮助你更好地理解这个问题及其两种解法!如果你有任何疑问或建议,请随时在评论区留言。
相关文章:
Java每日精进·45天挑战·Day19
第一部分:移除数字以形成最小数的贪心算法实现 在编程的世界里,我们经常遇到需要对字符串表示的数字进行操作的问题。今天,我们要深入探讨一个具体的挑战:给定一个以字符串形式表示的非负整数 num 和一个整数 k,我们的…...
区块链的交易管理和共识机制
区块链的交易管理和共识机制是其核心功能,以下为你详细介绍它们的实现方式: 交易管理的实现 交易发起 • 用户使用钱包软件创建一笔交易,该交易包含发送方地址、接收方地址、转账金额等关键信息。同时,发送方会使用自己的私钥对…...

最新国内 ChatGPT Plus/Pro 获取教程
最后更新版本:20250202 教程介绍: 本文将详细介绍如何快速获取一张虚拟信用卡,并通过该卡来获取ChatGPT Plus和ChatGPT Pro。 # 教程全程约15分钟开通ChatGPT Plus会员帐号前准备工作 一个尚未升级的ChatGPT帐号!一张虚拟信用卡…...

Apollo 9.0 速度动态规划决策算法 – path time heuristic optimizer
文章目录 1. 动态规划2. 采样3. 代价函数3.1 障碍物代价3.2 距离终点代价3.3 速度代价3.4 加速度代价3.5 jerk代价 4. 回溯 这一章将来讲解速度决策算法,也就是SPEED_HEURISTIC_OPTIMIZER task里面的内容。Apollo 9.0使用动态规划算法进行速度决策,从类名…...
Apache Iceberg 与 Apache Hudi:数据湖领域的双雄对决
在数据存储和处理不断发展的领域中,数据湖仓的概念已经崭露头角,成为了一种变革性的力量。数据湖仓结合了数据仓库和数据湖的最佳元素,提供了一个统一的平台,支持数据科学、商业智能、人工智能/机器学习以及临时报告等多种关键功能…...
【LeetCode Hot100 普通数组】最大子数组和、合并区间、旋转数组、除自身以外数组的乘积、缺失的第一个正整数
普通数组 1. 最大子数组和(Maximum Subarray)解题思路动态规划的优化解法(Kadane 算法)核心思想 代码解析 2. 合并区间(Merge Intervals)解题思路代码实现 3. 旋转数组(Rotate Array)…...

共享存储-一步一步部署ceph分布式文件系统
一、Ceph 简介 Ceph 是一个开源的分布式文件系统。因为它还支持块存储、对象存储,所以很自 然的被用做云计算框架 openstack 或 cloudstack 整个存储后端。当然也可以单独作 为存储,例如部署一套集群作为对象存储、SAN 存储、NAS 存储等。 二、ceph 支…...
19.Python实战:实现对博客文章的点赞系统
Flask博客点赞系统 一个基于Flask的简单博客系统,具有文章展示和点赞功能。系统使用MySQL存储数据,支持文章展示、点赞/取消点赞等功能。 功能特点 文章列表展示文章详情查看(模态框展示)点赞/取消点赞功能(每个IP只…...
【stm32】定时器输出PWM波形(hal库)
一. PWM基本原理 PWM是一种通过调节信号的占空比(Duty Cycle)来控制输出平均电压的技术。占空比是指高电平时间与整个周期时间的比值。例如: - 占空比为50%时,输出平均电压为电源电压的一半。 - 占空比为100%时,输出始…...

当Ollama遇上划词翻译:我的Windows本地AI服务搭建日记
🚀 实现Windows本地大模型翻译服务 - 基于OllamaFlask的划词翻译实践 🛠️ 步骤概要1️⃣ python 环境准备2️⃣ Ollama 安装3️⃣ 一个 Flask 服务4️⃣ Windows 服务化封装5️⃣ 测试本地接口6️⃣ 配置划词翻译自定义翻译源7️⃣ 效果展示8️⃣ debug…...
Linux上Elasticsearch 集群部署指南
Es 集群部署 Es 集群部署 Es 集群部署 准备好三台服务器。示例使用:110.0.5.141/142/143 1、es用户和用户组创建,使用root账号 groupadd esuseradd -g es es2、将es安装包和ik分词器上传到:/home/es/目录下(任意目录都行&#…...

字节Trae使用感想(后端)
前言 昨天分享了字节哥的Trae从0到1创作模式构建一个vue前端项目,今天又来试试她的后端项目能力。不是我舔,不得不说确实不错。可惜现在曾经没有好好学习,进不了字节。既然进不了字节,那我就用字节哥的产品吧。 后面有惊喜…...

国产编辑器EverEdit - 二进制模式下观察Window/Linux/MacOs换行符差异
1 换行符格式 1.1 应用场景 稍微了解计算机历史的人都知道, 计算机3大操作系统: Windows、Linux/Unix、MacOS,这3大系统对文本换行的定义各不相同,且互不相让,导致在文件的兼容性方面存在一些问题,比如它们…...

文心一言4月起全面免费,6月底开源新模型:AI竞争进入新阶段?
名人说:莫听穿林打叶声,何妨吟啸且徐行。—— 苏轼 Code_流苏(CSDN)(一个喜欢古诗词和编程的Coder😊) 目录 一、文心一言免费化的背后:AI成本与应用的双重驱动1️⃣成本下降,推动文心一言普及2…...

解锁机器学习算法 | 线性回归:机器学习的基石
在机器学习的众多算法中,线性回归宛如一块基石,看似质朴无华,却稳稳支撑起诸多复杂模型的架构。它是我们初涉机器学习领域时便会邂逅的算法之一,其原理与应用广泛渗透于各个领域。无论是预测房价走势、剖析股票市场波动࿰…...
如何使用Three.js制作3D月球与星空效果
目录 1. 基本设置2. 创建星空效果3. 创建月球模型4. 添加中文3D文字5. 光照与相机配置6. 动画与控制7. 响应式布局8. 结语 在本文中,我们将一起学习如何利用Three.js实现一个3D月球与星空的效果,并添加一些有趣的元素,比如中文3D文字和互动功…...
SQL语句语法
SQL数据库的结构为 库database 表table 段segment 行row 列column 或field SQL 语句主要分为以下几类: 数据定义语言(DDL):用于定义数据库对象,如数据库、表、视图、索引等。数据操作语言(DML)&…...
github上文件过大无法推送问题
GitHub 对文件大小有限制,超过 100 MB 的文件无法直接推送到仓库中。 解决思路: 使用 Git Large File Storage (Git LFS) 来管理大文件不上传对应的大文件 使用Git LFS: 1. 安装 Git LFS 首先,你需要安装 Git LFS。可以按照以…...
微信小程序的请求函数封装(ts版本,uniapp开发)
主要封装函数代码: interface HttpOptions {url: string;method?: string;headers?: { [key: string]: string };data?: any; }class Http {private timeout: number;private baseUrl: string;public constructor() { this.timeout 60 * 1000;this.baseUrl ht…...

Visual Studio Code支持WSL,直接修改linux/ubuntu中的文件
步骤1 开始通过 WSL 使用 VS Code | Microsoft Learn 点击远程开发扩展包。 步骤2 Remote Development - Visual Studio Marketplace 点击install, 允许打开Visual Studio Code。 步骤3 共有4项,一齐安装。 步骤4 在WSL Linux(Ubuntu)中…...

观成科技:隐蔽隧道工具Ligolo-ng加密流量分析
1.工具介绍 Ligolo-ng是一款由go编写的高效隧道工具,该工具基于TUN接口实现其功能,利用反向TCP/TLS连接建立一条隐蔽的通信信道,支持使用Let’s Encrypt自动生成证书。Ligolo-ng的通信隐蔽性体现在其支持多种连接方式,适应复杂网…...

Docker 运行 Kafka 带 SASL 认证教程
Docker 运行 Kafka 带 SASL 认证教程 Docker 运行 Kafka 带 SASL 认证教程一、说明二、环境准备三、编写 Docker Compose 和 jaas文件docker-compose.yml代码说明:server_jaas.conf 四、启动服务五、验证服务六、连接kafka服务七、总结 Docker 运行 Kafka 带 SASL 认…...
Objective-C常用命名规范总结
【OC】常用命名规范总结 文章目录 【OC】常用命名规范总结1.类名(Class Name)2.协议名(Protocol Name)3.方法名(Method Name)4.属性名(Property Name)5.局部变量/实例变量(Local / Instance Variables&…...

江苏艾立泰跨国资源接力:废料变黄金的绿色供应链革命
在华东塑料包装行业面临限塑令深度调整的背景下,江苏艾立泰以一场跨国资源接力的创新实践,重新定义了绿色供应链的边界。 跨国回收网络:废料变黄金的全球棋局 艾立泰在欧洲、东南亚建立再生塑料回收点,将海外废弃包装箱通过标准…...
汇编常见指令
汇编常见指令 一、数据传送指令 指令功能示例说明MOV数据传送MOV EAX, 10将立即数 10 送入 EAXMOV [EBX], EAX将 EAX 值存入 EBX 指向的内存LEA加载有效地址LEA EAX, [EBX4]将 EBX4 的地址存入 EAX(不访问内存)XCHG交换数据XCHG EAX, EBX交换 EAX 和 EB…...

ios苹果系统,js 滑动屏幕、锚定无效
现象:window.addEventListener监听touch无效,划不动屏幕,但是代码逻辑都有执行到。 scrollIntoView也无效。 原因:这是因为 iOS 的触摸事件处理机制和 touch-action: none 的设置有关。ios有太多得交互动作,从而会影响…...

pikachu靶场通关笔记22-1 SQL注入05-1-insert注入(报错法)
目录 一、SQL注入 二、insert注入 三、报错型注入 四、updatexml函数 五、源码审计 六、insert渗透实战 1、渗透准备 2、获取数据库名database 3、获取表名table 4、获取列名column 5、获取字段 本系列为通过《pikachu靶场通关笔记》的SQL注入关卡(共10关࿰…...

【Oracle】分区表
个人主页:Guiat 归属专栏:Oracle 文章目录 1. 分区表基础概述1.1 分区表的概念与优势1.2 分区类型概览1.3 分区表的工作原理 2. 范围分区 (RANGE Partitioning)2.1 基础范围分区2.1.1 按日期范围分区2.1.2 按数值范围分区 2.2 间隔分区 (INTERVAL Partit…...

STM32HAL库USART源代码解析及应用
STM32HAL库USART源代码解析 前言STM32CubeIDE配置串口USART和UART的选择使用模式参数设置GPIO配置DMA配置中断配置硬件流控制使能生成代码解析和使用方法串口初始化__UART_HandleTypeDef结构体浅析HAL库代码实际使用方法使用轮询方式发送使用轮询方式接收使用中断方式发送使用中…...

图解JavaScript原型:原型链及其分析 | JavaScript图解
忽略该图的细节(如内存地址值没有用二进制) 以下是对该图进一步的理解和总结 1. JS 对象概念的辨析 对象是什么:保存在堆中一块区域,同时在栈中有一块区域保存其在堆中的地址(也就是我们通常说的该变量指向谁&…...