力扣热门算法题 135. 分发糖果,146. LRU 缓存,148. 排序链表

news2024/9/23 1:23:58

135. 分发糖果,146. LRU 缓存,148. 排序链表,每题做详细思路梳理,配套Python&Java双语代码, 2024.03.28 可通过leetcode所有测试用例。

目录

135. 分发糖果

解题思路

完整代码

Python

Java

146. LRU 缓存

解题思路

完整代码

Python

Java

148. 排序链表

解题思路

完整代码

Python

Java


135. 分发糖果

n 个孩子站成一排。给你一个整数数组 ratings 表示每个孩子的评分。

你需要按照以下要求,给这些孩子分发糖果:

  • 每个孩子至少分配到 1 个糖果。
  • 相邻两个孩子评分更高的孩子会获得更多的糖果。

请你给每个孩子分发糖果,计算并返回需要准备的 最少糖果数目 。

示例 1:

输入:ratings = [1,0,2]
输出:5
解释:你可以分别给第一个、第二个、第三个孩子分发 2、1、2 颗糖果。

示例 2:

输入:ratings = [1,2,2]
输出:4
解释:你可以分别给第一个、第二个、第三个孩子分发 1、2、1 颗糖果。
     第三个孩子只得到 1 颗糖果,这满足题面中的两个条件。

解题思路

这个问题可以通过使用贪心算法来解决。解题的关键在于确保每个孩子都至少得到一个糖果,并且在满足相邻孩子之间的评分差异时,使用尽可能少的糖果。解题步骤如下:

  1. 初始化:创建一个与 ratings 长度相同的数组 candies,初始时每个孩子都分配 1 个糖果,即 candies[i] = 1

  2. 从左向右扫描:遍历 ratings 数组,从第二个元素开始,比较当前孩子和前一个孩子的评分。如果当前孩子的评分高于前一个孩子,那么当前孩子的糖果数应该比前一个孩子多一个,即 candies[i] = candies[i-1] + 1

  3. 从右向左扫描:再次遍历 ratings 数组,这次是从倒数第二个元素向第一个元素遍历。比较当前孩子和后一个孩子的评分。如果当前孩子的评分高于后一个孩子,并且当前孩子的糖果数不大于后一个孩子,那么当前孩子的糖果数应该比后一个孩子多一个,即 candies[i] = max(candies[i], candies[i+1] + 1)

  4. 计算总糖果数:最后,将 candies 数组中的所有值相加,得到的总和就是需要准备的最少糖果数目。

完整代码

Python
class Solution:
    def candy(self, ratings: List[int]) -> int:
        n = len(ratings)
        candies = [1] * n  # Step 1: Initialize

        # Step 2: Scan from left to right
        for i in range(1, n):
            if ratings[i] > ratings[i - 1]:
                candies[i] = candies[i - 1] + 1

        # Step 3: Scan from right to left
        for i in range(n - 2, -1, -1):
            if ratings[i] > ratings[i + 1]:
                candies[i] = max(candies[i], candies[i + 1] + 1)

        # Step 4: Calculate the total number of candies
        return sum(candies)
Java
public class Solution {
    public int candy(int[] ratings) {
        int n = ratings.length;
        int[] candies = new int[n];
        Arrays.fill(candies, 1);  // Step 1: Initialize

        // Step 2: Scan from left to right
        for (int i = 1; i < n; i++) {
            if (ratings[i] > ratings[i - 1]) {
                candies[i] = candies[i - 1] + 1;
            }
        }

        // Step 3: Scan from right to left
        for (int i = n - 2; i >= 0; i--) {
            if (ratings[i] > ratings[i + 1]) {
                candies[i] = Math.max(candies[i], candies[i + 1] + 1);
            }
        }

        // Step 4: Calculate the total number of candies
        int totalCandies = 0;
        for (int candy : candies) {
            totalCandies += candy;
        }
        return totalCandies;
    }
}

146. LRU 缓存

请你设计并实现一个满足  LRU (最近最少使用) 缓存 约束的数据结构。

实现 LRUCache 类:

  • LRUCache(int capacity) 以 正整数 作为容量 capacity 初始化 LRU 缓存
  • int get(int key) 如果关键字 key 存在于缓存中,则返回关键字的值,否则返回 -1 。
  • void put(int key, int value) 如果关键字 key 已经存在,则变更其数据值 value ;如果不存在,则向缓存中插入该组 key-value 。如果插入操作导致关键字数量超过 capacity ,则应该 逐出 最久未使用的关键字。

函数 get 和 put 必须以 O(1) 的平均时间复杂度运行。

示例:

输入
["LRUCache", "put", "put", "get", "put", "get", "put", "get", "get", "get"]
[[2], [1, 1], [2, 2], [1], [3, 3], [2], [4, 4], [1], [3], [4]]
输出
[null, null, null, 1, null, -1, null, -1, 3, 4]

解释
LRUCache lRUCache = new LRUCache(2);
lRUCache.put(1, 1); // 缓存是 {1=1}
lRUCache.put(2, 2); // 缓存是 {1=1, 2=2}
lRUCache.get(1);    // 返回 1
lRUCache.put(3, 3); // 该操作会使得关键字 2 作废,缓存是 {1=1, 3=3}
lRUCache.get(2);    // 返回 -1 (未找到)
lRUCache.put(4, 4); // 该操作会使得关键字 1 作废,缓存是 {4=4, 3=3}
lRUCache.get(1);    // 返回 -1 (未找到)
lRUCache.get(3);    // 返回 3
lRUCache.get(4);    // 返回 4

解题思路

  1. 数据结构设计

    • 定义双向链表的节点类,节点包含 keyvalueprevnext 四个属性。
    • 定义 LRUCache 类,包含 capacitysizecache(哈希表)和两个哨兵节点 headtail 来表示双向链表的头部和尾部。
  2. 辅助函数

    • addNode(Node node):在双向链表的头部添加一个新节点。
    • removeNode(Node node):从链表中删除一个节点。
    • moveToHead(Node node):将一个存在的节点移动到双向链表的头部。
    • popTail():弹出双向链表尾部的节点,并返回该节点。
  3. 主要操作

    • LRUCache(int capacity):初始化 LRU 缓存。
    • int get(int key):如果关键字 key 存在于缓存中,则返回关键字的值,否则返回 -1。如果 key 存在,还需要将对应的节点移动到双向链表的头部。
    • void put(int key, int value):如果关键字 key 已经存在,则变更其数据值 value 并移动到双向链表的头部;如果不存在,则向缓存中插入该组 key-value。如果插入操作导致关键字数量超过 capacity,则需要从双向链表的尾部删除最久未使用的节点,并且在哈希表中删除对应的项。

完整代码

Python
class DLinkedNode():
    def __init__(self):
        self.key = 0
        self.value = 0
        self.prev = None
        self.next = None

class LRUCache:

    def _add_node(self, node):
        node.prev = self.head
        node.next = self.head.next

        self.head.next.prev = node
        self.head.next = node

    def _remove_node(self, node):
        prev = node.prev
        new = node.next

        prev.next = new
        new.prev = prev

    def _move_to_head(self, node):
        self._remove_node(node)
        self._add_node(node)

    def _pop_tail(self):
        res = self.tail.prev
        self._remove_node(res)
        return res

    def __init__(self, capacity: int):
        self.cache = {}
        self.size = 0
        self.capacity = capacity
        self.head, self.tail = DLinkedNode(), DLinkedNode()

        self.head.next = self.tail
        self.tail.prev = self.head

    def get(self, key: int) -> int:
        node = self.cache.get(key, None)
        if not node:
            return -1

        self._move_to_head(node)

        return node.value

    def put(self, key: int, value: int) -> None:
        node = self.cache.get(key)

        if not node:
            newNode = DLinkedNode()
            newNode.key = key
            newNode.value = value

            self.cache[key] = newNode
            self._add_node(newNode)

            self.size += 1

            if self.size > self.capacity:
                tail = self._pop_tail()
                del self.cache[tail.key]
                self.size -= 1
        else:
            node.value = value
            self._move_to_head(node)
Java

class LRUCache {
    class DLinkedNode {
        int key;
        int value;
        DLinkedNode prev;
        DLinkedNode next;
    }

    private void addNode(DLinkedNode node) {
        node.prev = head;
        node.next = head.next;
        head.next.prev = node;
        head.next = node;
    }

    private void removeNode(DLinkedNode node) {
        DLinkedNode prev = node.prev;
        DLinkedNode next = node.next;
        prev.next = next;
        next.prev = prev;
    }

    private void moveToHead(DLinkedNode node) {
        removeNode(node);
        addNode(node);
    }

    private DLinkedNode popTail() {
        DLinkedNode res = tail.prev;
        removeNode(res);
        return res;
    }

    private HashMap<Integer, DLinkedNode> cache = new HashMap<>();
    private int size;
    private int capacity;
    private DLinkedNode head, tail;

    public LRUCache(int capacity) {
        this.size = 0;
        this.capacity = capacity;
        head = new DLinkedNode();
        tail = new DLinkedNode();
        head.next = tail;
        tail.prev = head;
    }
    
    public int get(int key) {
        DLinkedNode node = cache.get(key);
        if (node == null) return -1;
        moveToHead(node);
        return node.value;
    }
    
    public void put(int key, int value) {
        DLinkedNode node = cache.get(key);

        if (node == null) {
            DLinkedNode newNode = new DLinkedNode();
            newNode.key = key;
            newNode.value = value;

            cache.put(key, newNode);
            addNode(newNode);

            ++size;

            if (size > capacity) {
                DLinkedNode tail = popTail();
                cache.remove(tail.key);
                --size;
            }
        } else {
            node.value = value;
            moveToHead(node);
        }
    }
}

148. 排序链表

给你链表的头结点 head ,请将其按 升序 排列并返回 排序后的链表 。

示例 1:

输入:head = [4,2,1,3]
输出:[1,2,3,4]

示例 2:

输入:head = [-1,5,3,4,0]
输出:[-1,0,3,4,5]

示例 3:

输入:head = []
输出:[]

解题思路

对链表进行排序可以通过多种算法来实现,其中归并排序因其稳定的 O(nlogn) 时间复杂度而广泛应用于链表排序中。链表的归并排序可以分为以下几个步骤:

  1. 寻找中点:使用快慢指针法找到链表的中点(慢指针每次前进一步,快指针每次前进两步,当快指针到达末尾时,慢指针即在中点)。

  2. 切分链表:将链表从中点处切分为两个链表,进行递归排序。

  3. 合并链表:将两个已排序的链表合并为一个有序链表。

完整代码

Python
# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    def sortList(self, head: Optional[ListNode]) -> Optional[ListNode]:
        # 如果链表为空或者只有一个节点,直接返回
        if not head or not head.next:
            return head
        
        # 快慢指针找到中点
        slow, fast = head, head.next
        while fast and fast.next:
            slow = slow.next
            fast = fast.next.next
        
        # 分割链表
        mid, slow.next = slow.next, None

        # 递归排序
        left, right = self.sortList(head), self.sortList(mid)

        # 合并两个有序链表
        return self.merge(left, right)

    # 合并两个有序链表的函数
    def merge(self, l1: ListNode, l2: ListNode) -> ListNode:
        dummy = tail = ListNode()
        while l1 and l2:
            if l1.val < l2.val:
                tail.next, l1 = l1, l1.next
            else:
                tail.next, l2 = l2, l2.next
            tail = tail.next
        tail.next = l1 or l2
        return dummy.next
Java
/**
 * 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; }
 * }
 */
public class Solution {
    public ListNode sortList(ListNode head) {
        if (head == null || head.next == null) {
            return head;
        }

        // Step 1: 寻找中点
        ListNode slow = head, fast = head.next;
        while (fast != null && fast.next != null) {
            slow = slow.next;
            fast = fast.next.next;
        }

        // Step 2: 切分链表
        ListNode mid = slow.next;
        slow.next = null;

        // Step 3: 递归排序
        ListNode left = sortList(head);
        ListNode right = sortList(mid);

        // Step 4: 合并链表
        ListNode dummy = new ListNode(0);
        ListNode tail = dummy;
        while (left != null && right != null) {
            if (left.val < right.val) {
                tail.next = left;
                left = left.next;
            } else {
                tail.next = right;
                right = right.next;
            }
            tail = tail.next;
        }
        tail.next = (left != null) ? left : right;
        return dummy.next;
    }
}

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

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

相关文章

Mybatis别名 动态sql语句 分页查询

给Mybatis的实体类起别名 给Mybatis的xml文件注册mapper映射文件 动态sql语句 1 if 2 choose 3 where 4 foreach 一&#xff09;if 查询指定名称商品信息 语法&#xff1a; SELECT * FROM goods where 11 <if test "gName!null"> and g.g_name like co…

|行业洞察·手机|《2024手机行业及营销趋势报告-18页》

报告的主要内容解读&#xff1a; 手机行业概述及品牌分布&#xff1a; 2022年&#xff0c;受疫情影响&#xff0c;中国国内手机市场出货量下降22.6%&#xff0c;总计2.72亿部。5G手机市场占有率中&#xff0c;苹果领先&#xff0c;其次是vivo、OPPO和华为。消费者换机时更注重性…

【MagicDrive环境配置】新手配俩星期版

1.创建一个新的环境conda create -n newdrive python3.8 2.激活该环境conda activate newdrive 3.下载MagicDrive源码 git clone --recursive https://github.com/cure-lab/MagicDrive.git&#xff0c;如果出现时间超时八成是网的问题&#xff0c;直接自己下载解压就好 3.我的…

【群智能算法改进】一种改进的同核分子优化算法 IHMO算法【Matlab代码#71】

文章目录 【获取资源请见文章第5节&#xff1a;资源获取】1. 原始HMO算法2. 改进HMO算法2.1 改进的距离减小因子2.2 黄金正弦策略扰动 3. 部分代码展示4. 仿真结果展示5. 资源获取说明 【获取资源请见文章第5节&#xff1a;资源获取】 1. 原始HMO算法 同核分子优化算法&#x…

HarmonyOS 应用开发之UIAbility组件生命周期

概述 当用户打开、切换和返回到对应应用时&#xff0c;应用中的UIAbility实例会在其生命周期的不同状态之间转换。UIAbility类提供了一系列回调&#xff0c;通过这些回调可以知道当前UIAbility实例的某个状态发生改变&#xff0c;会经过UIAbility实例的创建和销毁&#xff0c;…

网络原理-传输层-UDP报文结构

本文介绍UDP报文 有很多友友搞不清楚UDP报文的详细结构还有TCP的详细结构,所以专门分开来讲 以免弄混. 首先我们先看一下整个UDP结构,让大家有一个全方面的认识 下面我们来详细解释UDP报 16位源端口号(本机):就是2字节大小,16个二进制位. 16位目的端口号(目的机):也是2字节…

如何构建一台机器学习服务器

系统信息 系统安装 系统安装这里就不再赘述&#xff0c;推荐使用ventory作为PE盘&#xff0c;来安装系统&#xff0c;这样方便快捷&#xff0c;可同时包含多个镜像&#xff0c;无需重复制作&#xff0c;需要注意的是在安装系统的时候需要手动进行分区&#xff0c;我们可以看一下…

uniApp使用XR-Frame创建3D场景(3)光源投影的运用。

上一篇讲解了如何在uniApp中创建xr-frame子组件并创建简单的3D场景。 这篇我们讲解光源在场景中的运用以及相关属性。 在子组件 xr-start的index.wxml文件中我们加入如下代码 <xr-scene render-system"alpha:true" bind:ready"handleReady"><xr…

睿尔曼超轻量仿人机械臂之复合机器人底盘介绍及接口调用

机器人移动平台是一个包含完整成熟的感知、认知和定位导航能力的轮式机器人底盘产品级平台&#xff0c;产品致力于为各行业细分市场的商用轮式服务机器人提供一站式移动机器人解决方案&#xff0c;让合作伙伴专注在核心业务/人机交互的实现。以下是我司产品双臂机器人以及复合升…

主机安全-德迅卫士

什么是主机安全&#xff1f; 主机安全&#xff0c;其核心内容包括安全应用交付系统、应用监管系统、操作系统安全增强系统和运维安全管控系统。它的具体功能是指保证主机在数据存储和处理的保密性、完整性&#xff0c;可用性&#xff0c;它包括硬件、固件、系统软件的自身安全&…

HCIA-Datacom H12-811 题库补充(3/28)

完整题库及答案解析&#xff0c;请直接扫描上方二维码&#xff0c;持续更新中 OSPFv3使用哪个区域号标识骨干区域&#xff1f; A&#xff1a;0 B&#xff1a;3 C&#xff1a;1 D&#xff1a;2 答案&#xff1a;A 解析&#xff1a;AREA 号0就是骨干区域。 STP下游设备通知上游…

蓝桥杯_day6

文章目录 不同路径不同路径II拿金币珠宝的最高价值 不同路径 【题目描述】 一个机器人位于一个 m x n 网格的左上角 &#xff08;起始点在下图中标记为 “Start” &#xff09;。 机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角&#xff08;在下图中标记为…

啥也不会的大学生看过来,这8步就能系统入门stm32单片机???

大家好&#xff0c;今天给大家介绍啥也不会的大学生看过来&#xff0c;这8步就能系统入门stm32单片机&#xff0c;文章末尾附有分享大家一个资料包&#xff0c;差不多150多G。里面学习内容、面经、项目都比较新也比较全&#xff01;可进群免费领取。 对于没有任何基础的大学生来…

GPT:多轮对话并搭建简单的聊天机器人

1 多轮对话 多轮对话能力至关重要&#xff0c;它不仅能深化交流&#xff0c;精准捕捉对方意图&#xff0c;还能促进有效沟通&#xff0c;增强理解。在智能客服、教育辅导等领域&#xff0c;多轮对话更是提升服务质量、增强用户体验的关键。 注意&#xff1a;大模型没有多轮对话…

JAVA使用POI实现Excel单元格合并-02

JAVA使用POI实现Excel单元格合并 实现效果 解释&#xff1a;只要是遇见与前一行相同的数据就合并 引入jar <dependency><groupId>org.apache.poi</groupId><artifactId>poi-ooxml</artifactId><version>5.2.2</version></depe…

OpenCV 如何使用 XML 和 YAML 文件的文件输入和输出

返回&#xff1a;OpenCV系列文章目录&#xff08;持续更新中......&#xff09; 上一篇&#xff1a;如何利用OpenCV4.9离散傅里叶变换 下一篇: 目标 本文内容主要介绍&#xff1a; 如何使用 YAML 或 XML 文件打印和读取文件和 OpenCV 的文本条目&#xff1f;如何对 OpenCV …

如何选择合适的充电桩主控制板

充电桩主控制板是充电桩不可或缺的核心元件之一&#xff0c;它的功能多样&#xff0c;包括控制、保护、监测、报警和记录等。随着充电基础设施的不断完善&#xff0c;选择合适的充电桩主控制板成为设计过程中至关重要的一环。然而&#xff0c;在市场上琳琅满目的产品中做出选择…

20221124 kafka实时数据写入Redis

一、上线结论 实现了将用户线上实时浏览的沉浸式视频信息&#xff0c;保存在Redis中这样一个功能。为实现沉浸式视频离线推荐到实时推荐提供了强有力的支持。目前只是应用在沉浸式场景&#xff0c;后续也能扩展到其他所有场景。用于两个场景&#xff1a;&#xff08;1&#xf…

一分钟开服 《幻兽帕鲁》游戏专属服务器by京东云主机

使用京东云服务器搭建幻兽帕鲁Palworld游戏联机服务器教程&#xff0c;非常简单&#xff0c;京东云推出幻兽帕鲁镜像系统&#xff0c;镜像直接选择幻兽帕鲁镜像即可一键自动部署&#xff0c;不需要手动操作&#xff0c;真正的新手0基础部署幻兽帕鲁&#xff0c;阿腾云atengyun.…

创新指南|如何将人工智能应用于未来的创新管理——并不断付诸实践

ChatGPT 的推出加剧了围绕人工智能的炒作&#xff0c;现在我们看到了前所未有的巨大进展。对于我们这些热衷于创新的人来说&#xff0c;这是一个激动人心的时刻。他们正在共同采取措施&#xff0c;充分利用人工智能进行创新管理。本文将阐述人工智能能为创新管理做什么&#xf…