【Py/Java/C++三种语言详解】LeetCode每日一题240122【贪心】LeetCode670、最大交换

文章目录

  • 题目链接
  • 题目描述
  • 解题思路
    • 为什么是贪心
    • 一个带图的例子
  • 代码
    • python
    • java
    • cpp
    • 时空复杂度
  • 华为OD算法/大厂面试高频题算法练习冲刺训练

题目链接

LeetCode670、最大交换

题目描述

给定一个非负整数数组 nums 和一个整数 k ,你需要将这个数组分成 k 个非空的连续子数组。

设计一个算法使得这 k 个子数组各自和的最大值最小。

示例 1

输入:nums = [7,2,5,10,8], k = 2
输出:18
解释: 一共有四种方法将 nums 分割为 2 个子数组。 其中最好的方式是将其分为 [7,2,5] 和 [10,8] 。 因为此时这两个子数组各自的和的最大值为18,在所有情况中最小。

示例 2

输入:nums = [1,2,3,4,5], k = 2
输出:9

示例 3

输入:nums = [1,4,4], k = 3
输出:4

提示

  • 1 <= nums.length <= 1000
  • 0 <= nums[i] <= 10(6)
  • 1 <= k <= min(50, nums.length)

解题思路

数据范围(数字的长度)最大为8,时间复杂度为O(N^3)的暴力法可以通过。

所谓暴力法,就是枚举出所有不同的下标对(i, j),交换s[i]s[j],找到交换完之后最大的那一组。

思路较为简单,故在此略去不表。一下讨论贪心的做法。

为什么是贪心

由于最多只能交换一次,贪心地思考一下这个问题:我们什么希望进行一个怎么样的交换?

换言之,怎么交换才能使得数字尽可能地大

考虑例子

9091987

原字符串中的第三个"9"最大且位置尽可能靠后的数字,这个字符应该优先地被交换到尽可能前的位置。由于索引0的数字是"9",所以考虑索引1的字符"0"和第三个"9"交换。得到答案

9991087

从这个例子可以看出贪心的策略是:

  1. 首选一个尽可能大的数字(比如示例中选择字符"9"
  2. 如果有多个最大的数字,则优先选择位置尽可能靠后的那个(比如示例中选择第三个"9"
  3. 将该数字交换到尽可能靠前的位置,即交换到第一个小于该数字的位置(比如示例中索引1的位置)。

所以考虑逆序遍历原数字字符串(为了方便交换操作,改成数组来操作),并且使用一个栈(类似一个单调栈),储存原数字从右往左看遇到的更大的数字的下标

stack = list()
for i in range(n-1, -1, -1):
    if not stack or lst[i] > lst[stack[-1]]:
        stack.append(i)

最终这个栈一定会满足以下条件:

  • 栈中储存的是原数字字符串的数字的下标i
  • i的取值自栈底向栈顶递减,即栈顶元素stack[-1]是在数字lst中位置最靠前的下标(满足了上述贪心策略2
  • lst[i]的取值自栈底向栈顶递增,即栈顶元素对应的下标在数字数组中的取值lst[i]是最大的数字(满足了上述贪心策略1

以例子num = 9091987为例,栈中的结果是储存了最后三个数字"987"的下标,即stack = [6, 5, 4]

接下来要考虑如何实现上述贪心策略的第三点。

我们可以从头到尾遍历原数字数组lst,将下标i和栈顶元素stack[-1]、以及下标i对应的数字lst[i]和栈顶元素对应的数字lst[stack[-1]]进行比较。若

  • i < stack[-1],说明此时下标i的位置位于stack[-1]的左边,可以继续进行后续判断。若
    • lst[i] < lst[stack[-1]],说明此时可以交换位置istack[-1]的两个数字,交换之且退出循环
    • lst[i] >= lst[stack[-1]],说明此时不能进行交换,i需要继续增大
  • i >= stack[-1],说明此时下标i的位置已经不再位于stack[-1]的左边,此时不能再考虑栈顶元素,应该将其弹出

另外,由于涉及弹出操作,如果出现空栈情况,但尚未进行交换,则说明原数字数字本身就是一个非递增序列,需要退出循环。综上,上述贪心操作的代码为

for i in range(n):
    if not stack:
        break
    if i > stack[-1]:
        if lst[i] < lst[stack[-1]]:
            lst[i], lst[stack[-1]] = lst[stack[-1]], lst[i]
            ans = "".join(lst)
            break
        else:
            continue
    else:
        stack.pop()

一个带图的例子

再举一个例子,num = "9987687676",答案应该为ans = "9988677676",可以做出如下图
在这里插入图片描述

逆序遍历数组lst,构建栈stack = [8, 7, 4, 1],为可能进行交换的那些对应较大数字且靠后的位置。
在这里插入图片描述

正序遍历i,反复拿出栈顶索引对应的元素lst[stack[-1]]对应的数字和i对应的元素lst[i]进行比较。会经历如下过程。

在这里插入图片描述

i < stack[-1],但lst[i] >= lst[stack[-1]]。不能做交换,i增加。

在这里插入图片描述

i >= stack[-1],即i的位置不位于stack[-1]的左边,stack[-1]出栈,i增加。

在这里插入图片描述

i < stack[-1],但lst[i] >= lst[stack[-1]]。不能做交换,i增加。

在这里插入图片描述

i < stack[-1],且lst[i] < lst[stack[-1]]。进行交换,得到ans = "9988677676",是可以得到的数字最大的结果。

代码

python

# 贪心+栈:O(N)
class Solution:
    def maximumSwap(self, num: int) -> int:
        # 用列表的形式储存数字num
        lst = list(str(num))
        # 获得数字num的位数(即lst的长度)
        n = len(lst)

        # 构建一个栈,储存原字符串从右往左看遇到的更大数字的下标
        stack = list()

        # 逆序遍历字符串s
        for i in range(n-1, -1, -1):
            # 如果栈是空栈,或者当前下标i对应的数字lst[i]大于栈顶下标对应的数字lst[stack[-1]]
            # 则将索引i加入stack
            if not stack or lst[i] > lst[stack[-1]]:
                stack.append(i)
        
        # 正序遍历列表lst
        for i in range(n):
            # 若出现空栈情况,则退出循环
            if not stack:
                break
            # 如果当前下标i位于栈顶元素stack[-1]的左边
            # 则可以进行后续判断
            if i < stack[-1]:
                # 若当前数字小于栈顶元素对应的数字,则可以进行交换
                if lst[i] < lst[stack[-1]]:
                    lst[i], lst[stack[-1]] = lst[stack[-1]], lst[i]
                    return int("".join(lst))
                # 否则,考虑下一个i,这里的else也可以不写
                else:
                    continue
            # 如果当前下标i不位于栈顶元素stack[-1]的左边
            # 则弹出栈顶元素,考虑下一个较小但是位于较右位置的数字
            else:
                stack.pop()

        return num
                

java

public class Solution {
    public int maximumSwap(int num) {
        char[] chars = Integer.toString(num).toCharArray();
        int n = chars.length;
        int[] stack = new int[n];

        int top = -1;
        for (int i = n - 1; i >= 0; i--) {
            if (top == -1 || chars[i] > chars[stack[top]]) {
                stack[++top] = i;
            }
        }

        for (int i = 0; i < n; i++) {
            if (top == -1) {
                break;
            }

            if (i < stack[top]) {
                if (chars[i] < chars[stack[top]]) {
                    char temp = chars[i];
                    chars[i] = chars[stack[top]];
                    chars[stack[top]] = temp;
                    return Integer.parseInt(new String(chars));
                }
            } else {
                top--;
            }
        }

        return num;
    }
}

cpp

class Solution {
public:
    int maximumSwap(int num) {
        std::string numStr = std::to_string(num);
        int n = numStr.length();
        std::vector<int> stack;

        for (int i = n - 1; i >= 0; i--) {
            if (stack.empty() || numStr[i] > numStr[stack.back()]) {
                stack.push_back(i);
            }
        }

        for (int i = 0; i < n; i++) {
            if (stack.empty()) {
                break;
            }

            if (i < stack.back()) {
                if (numStr[i] < numStr[stack.back()]) {
                    std::swap(numStr[i], numStr[stack.back()]);
                    return std::stoi(numStr);
                }
            } else {
                stack.pop_back();
            }
        }

        return num;
    }
};

时空复杂度

时间复杂度:O(N)。仅需一次遍历所有数字。

空间复杂度:O(1)。栈所占空间,最大为9,可视为常数级别空间。


华为OD算法/大厂面试高频题算法练习冲刺训练

  • 华为OD算法/大厂面试高频题算法冲刺训练目前开始常态化报名!目前已服务100+同学成功上岸!

  • 课程讲师为全网50w+粉丝编程博主@吴师兄学算法 以及小红书头部编程博主@闭着眼睛学数理化

  • 每期人数维持在20人内,保证能够最大限度地满足到每一个同学的需求,达到和1v1同样的学习效果!

  • 60+天陪伴式学习,40+直播课时,300+动画图解视频,300+LeetCode经典题,200+华为OD真题/大厂真题,还有简历修改、模拟面试、专属HR对接将为你解锁

  • 可上全网独家的欧弟OJ系统练习华子OD、大厂真题

  • 可查看链接 大厂真题汇总 & OD真题汇总(持续更新)

  • 绿色聊天软件戳 od1336了解更多

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

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

相关文章

深入浅出 diffusion(4):pytorch 实现简单 diffusion

1. 训练和采样流程 2. 无条件实现 import torch, time, os import numpy as np import torch.nn as nn import torch.optim as optim from torchvision.datasets import MNIST from torchvision import transforms from torch.utils.data import DataLoader from torchvision.…

智能分析网关V4智慧冶金工厂视频智能监管方案

一、背景与需求 随着工业4.0的推进&#xff0c;冶金行业正面临着转型升级的压力。为了提高生产效率、降低能耗、保障安全&#xff0c;冶金智能工厂视频监管方案应运而生。该方案通过高清摄像头、智能分析技术、大数据处理等手段&#xff0c;对工厂进行全方位、实时监控&#xf…

matlab appdesigner系列-图窗工具2-工具栏

工具栏&#xff0c;就是一般在任意软件界面上方的工具菜单栏 示例&#xff1a;工具菜单绘制正弦函数 操作步骤如下&#xff1a; 1&#xff09;将坐标区和工具栏拖拽到画布上 2)点击工具栏的号&#xff0c;可以看到可以添加2种工具&#xff0c;按钮工具和切换工具&#xff0c…

Unity 代理模式(实例详解)

文章目录 实例1&#xff1a;资源加载代理&#xff08;Asset Loading Proxy&#xff09;实例2&#xff1a;网络请求代理&#xff08;Network Request Proxy&#xff09;实例3&#xff1a;性能优化代理&#xff08;Performance Optimization Proxy&#xff09;实例4&#xff1a;权…

LC 2846. 边权重均等查询

2846. 边权重均等查询 难度&#xff1a; 困难 题目大意&#xff1a; 现有一棵由 n 个节点组成的无向树&#xff0c;节点按从 0 到 n - 1 编号。给你一个整数 n 和一个长度为 n - 1 的二维整数数组 edges &#xff0c;其中 edges[i] [ui, vi, wi] 表示树中存在一条位于节点 …

银行数据仓库体系实践(11)--数据仓库开发管理系统及开发流程

数据仓库管理着整个银行或公司的数据&#xff0c;数据结构复杂&#xff0c;数据量庞大&#xff0c;任何一个数据字段的变化或错误都会引起数据错误&#xff0c;影响数据应用&#xff0c;同时业务的发展也带来系统不断升级&#xff0c;数据需求的不断增加&#xff0c;数据仓库需…

EventSource 长链接执行

EventSource 说明文档MDN 其他参考文档 一、利用node启服务 import fs from fs import express from express const app express() // eventSource 仅支持 get 方法 // 服务器端发送的数据必须是纯文本格式&#xff0c;不能是二进制数据。 app.get(/api, (req, res) > …

项目性能优化之用compression-webpack-plugin插件开启gzip压缩

背景&#xff1a;vue项目打包发布后&#xff0c;部分js、css文件体积较大导致页面卡顿&#xff0c;于是使用webpack插件compression-webpack-plugin开启gzip压缩 前端配置vue.config.js 先通过npm下载compression-webpack-plugin包&#xff0c;npm i compression-webpack-plug…

Android SharedPreferences源码分析

文章目录 Android SharedPreferences源码分析概述基本使用源码分析获取SP对象初始化和读取数据写入数据MemoryCommitResultcommitToMemory()commit()apply()enqueueDiskWrite()writeToFile() 主动等待写回任务结束 总结 Android SharedPreferences源码分析 概述 SharedPrefer…

EXCEL VBA抓取网页JSON数据并解析

EXCEL VBA抓取网页JSON数据并解析 链接地址&#xff1a; https://api.api68.com/CQShiCai/getBaseCQShiCaiList.do?lotCode10036&date2024-01-26 Sub test() On Error Resume Next Sheet.Select Sheet1.Cells.ClearContents [a1:g1] Split("preDrawIssue|preDrawTi…

Ubuntu20.04添加桌面启动、侧边栏启动和终端启动

桌面启动 新建XX.desktop文件 在桌面新建一个XX.desktop文件&#xff0c;以QtCreator为例。 &#xff08;注意这里不能使用sudo&#xff0c;因为这样会把文件的权限归为root&#xff0c;导致后续设置可执行程序不方便&#xff09; gedit qtcreator.desktop在XX.desktop文件中…

第14次修改了可删除可持久保存的前端html备忘录:增加一个翻牌钟,修改背景主题:现代深色

第14次修改了可删除可持久保存的前端html备忘录&#xff1a;增加一个翻牌钟&#xff0c;修改背景主题&#xff1a;现代深色 备忘录代码 <!DOCTYPE html> <html lang"zh"> <head><meta charset"UTF-8"><meta http-equiv"X…

设计模式—行为型模式之责任链模式

设计模式—行为型模式之责任链模式 责任链&#xff08;Chain of Responsibility&#xff09;模式&#xff1a;为了避免请求发送者与多个请求处理者耦合在一起&#xff0c;于是将所有请求的处理者通过前一对象记住其下一个对象的引用而连成一条链&#xff1b;当有请求发生时&am…

Flink面试题

0. 思维导图 1. 简单介绍一下Flink♥♥ Flink是一个分布式的计算框架&#xff0c;主要用于对有界和无界数据流进行有状态计算&#xff0c;其中有界数据流就是值离线数据&#xff0c;有明确的开始和结束时间&#xff0c;无界数据流就是指实时数据&#xff0c;源源不断没有界限&a…

ES文档索引、查询、分片、文档评分和分析器技术原理

技术原理 索引文档 索引文档分为单个文档和多个文档。 单个文档 新建单个文档所需要的步骤顺序&#xff1a; 客户端向 Node 1 发送新建、索引或者删除请求。节点使用文档的 _id 确定文档属于分片 0 。请求会被转发到 Node 3&#xff0c;因为分片 0 的主分片目前被分配在 …

Android源码设计模式解析与实战第2版笔记(二)

第二章 应用最广的模式 — 单例模式 单例模式的定义 确保某一个类只有一个实例&#xff0c;而且自行实例化并向整个系统提供这个实例。 单例模式的使用场景 确保某个类有且只有一个对象的场景&#xff0c;避免产生多个对象消耗过多的资源&#xff0c;或者某种类型的对象只应…

DT浏览器浏览网页的技巧

DT浏览器浏览网页的技巧&#xff1a; 1. 使用书签和收藏夹&#xff1a;将常用的网页添加到书签或收藏夹中&#xff0c;方便快速访问。 2. 善用搜索引擎&#xff1a;使用搜索引擎可以快速找到你需要的信息。在搜索时&#xff0c;可以使用关键词和筛选条件来精确查找。 3. 注意网…

【C/C++】详解程序环境和预处理(什么是程序环境?为什么要有程序环境?如何理解程序环境?)

目录 一、前言 二、 什么是程序环境&#xff1f; 三、 为什么要有程序环境&#xff1f; 四、如何理解程序环境&#xff1f; &#x1f34e; ANSI C 标准 &#x1f350; 翻译环境和执行环境 五、详解翻译环境和执行环境 &#x1f347;翻译环境&#xff08;重点&#xff01…

米贸搜|Meta金融科技行业广告政策Facebook

当前全球金融科技行业正处于快速发展阶段&#xff0c;作为全球最大的社交媒体网络之一&#xff0c;Meta平台为金融科技公司提供了一个重要的业务营销渠道&#xff0c;使其能够在广大用户群体中宣传和推广其产品和服务。 金融科技企业通过Meta平台投放广告&#xff0c;要注重政策…

Mac网线上网绿联扩展坞连接网线直接上网-无脑操作

声明&#xff1a;博主使用的绿联扩展坞 以下为绿联扩展坞Mac网线使用方法 1.首先需要下载电脑对应版本的驱动 直接点击即可下载 2. 下载好以后 解压 点进去 对应版本 博主直接使用最新的12-14 3. 安装包好了以后 会提示重启电脑 此时拔掉扩展坞 再重启动 拔掉扩展坞 再重启…