数组与贪心算法——605、121、122、561、455、575(5简1中)

news2024/11/24 20:57:44

605. 种花问题(简单)

假设有一个很长的花坛,一部分地块种植了花,另一部分却没有。可是,花不能种植在相邻的地块上,它们会争夺水源,两者都会死去。

给你一个整数数组 flowerbed 表示花坛,由若干 0 和 1 组成,其中 0 表示没种植花,1 表示种植了花。另有一个数 n ,能否在不打破种植规则的情况下种入 n 朵花?能则返回 true ,不能则返回 false 。

 解法一、贪心

先种满,数数满了多出来几朵,再讨论n在不在范围内。对边界要求有点高。。

题解里较完美的一个if条件:

 if ((i == 0 || f[i - 1] == 0) && f[i] == 0 && (i == m - 1 || f[i + 1] == 0))

class Solution {
    public boolean canPlaceFlowers(int[] flowerbed, int n) {
        int num = flowerbed.length;
        int res = 0;
        if(num == 1){
            return n==0 || flowerbed[0] == 0 && n == 1 ;
        }else if(num == 2){
            return n==0 || ((flowerbed[0] == 0 && flowerbed[1] == 0) && n == 1);
        }
        for(int i = 0; i < num;i++){
            if(i == 0 && flowerbed[0] == 0 && flowerbed[1] == 0){
                flowerbed[0] = 1;
                res++;
            }else if(i == num-1 && flowerbed[i-1] == 0 && flowerbed[i] == 0){
                res++;
            }else if(i > 0 && i < num - 1 && flowerbed[i] != 1 && flowerbed[i+1] != 1 && flowerbed[i-1] != 1){
                flowerbed[i] = 1;
                res++;
            }
        }
        return n <= res;
    }
}

121. 买卖股票的最佳时机(简单)

给定一个数组 prices ,它的第 i 个元素 prices[i] 表示一支给定股票第 i 天的价格。

你只能选择 某一天 买入这只股票,并选择在 未来的某一个不同的日子 卖出该股票。设计一个算法来计算你所能获取的最大利润。

返回你可以从这笔交易中获取的最大利润。如果你不能获取任何利润,返回 0 。 

解法一、暴力(超时)

一开始确实想不动脑子来着(

public class Solution {
    public int maxProfit(int[] prices) {
        int maxprofit = 0;
        for (int i = 0; i < prices.length - 1; i++) {
            for (int j = i + 1; j < prices.length; j++) {
                int profit = prices[j] - prices[i];
                if (profit > maxprofit) {
                    maxprofit = profit;
                }
            }
        }
        return maxprofit;
    }
}

解法二、类dp

但不需要维护一个dp数组,只需要维护一个从0-k(0<=k<n)的最小买入值就好

class Solution {
    public int maxProfit(int[] prices) {
        int min = prices[0];
        int profit = 0;
        for(int i = 1;i < prices.length;i++){
            profit = Math.max(prices[i] - min,profit);
            min = Math.min(min,prices[i]);
        }
        return profit;
    }
}

122. 买卖股票的最佳时机 II(中等)

给你一个整数数组 prices ,其中 prices[i] 表示某支股票第 i 天的价格。

在每一天,你可以决定是否购买和/或出售股票。你在任何时候 最多 只能持有 一股 股票。你也可以先购买,然后在 同一天 出售。

返回 你能获得的 最大 利润 。

解法一、贪心

本质思想就是一旦有钱赚马上买入卖出。注意:贪心只能模拟思想过程,不是实际交易过程。如对于[1,3,4],贪心是1买3卖、3买4卖,交易过程是1买4卖。两者利益等价,行为不等价。

本题还有很多其他类型,尤其是dp/递增栈,但果然还是放在dp专题里做比较好吧~这方面就不贪心了!

class Solution {
    public int maxProfit(int[] prices) {
        int profit = 0;
        if(prices.length < 2)return 0;
        for(int i = 1;i < prices.length;i++){
            if(prices[i] > prices[i-1])profit += prices[i] - prices[i-1];
        }
        return profit;
    }
}

561. 数组拆分(简单) 

给定长度为 2n 的整数数组 nums ,你的任务是将这些数分成 n 对, 例如 (a1, b1), (a2, b2), ..., (an, bn) ,使得从 1 到 n的 min(ai, bi) 总和最大。

返回该 最大总和 。

解法一、排序

要取最大,也就是尽量把小的和小的堆一起,大的和大的堆一起。所以先排序,排序后数组偶数位置的和就是所求。

class Solution {
    public int arrayPairSum(int[] nums) {
        Arrays.sort(nums);
        int n = nums.length,sum = 0;
        for(int i = 0;i < n;i +=2){
            sum+=nums[i];
        }
        return sum;
    }
}

解法二、数组排序

从代码示例那边看到的。这个和之前看到的那个取maxSum、minSum然后/2的技法其实有点像,桶排序虽然麻烦但是耗时真的很低。这里直接取gpt的解释吧。

  • index 用来追踪当前已经遍历的数值的累计个数。

  • res 是用于存储最终的结果。

每当 arr[i] > 0,意味着索引 i 对应的数值在 nums 中出现过,代码会根据当前的 index 和 arr[i] 的值来计算部分结果:

  • ((index + 1) % 2 + arr[i]) / 2 这个表达式与确定中位数位置相关,它用于决定是否将该数值纳入 res的计算。

  • (i - 10000) 将索引 i 转换回原来的数值范围(因为我们之前对 nums 的数值进行了偏移处理)。

最后,index = index + arr[i] 用于更新累计的数值个数。

((index + 1) % 2 + arr[i]) / 2 这个表达式的作用是用于控制在遍历过程中,是否选择将当前 i 对应的数值 (即 i - 10000) 贡献给最终的 res 结果。让我们一步一步拆解它的含义:

1. index + 1

index 是用来记录遍历到当前位置之前,总共处理过的元素的个数。index + 1 表示当前的元素是所有已经遍历过的元素中的第几个。

2. % 2

对 index + 1 取模 2 的作用是确定当前这个元素是偶数还是奇数。它会返回两种情况:

  • 当 index + 1 是奇数时,(index + 1) % 2 = 1

  • 当 index + 1 是偶数时,(index + 1) % 2 = 0

这个结果决定了后续表达式的一个偏移调整。

3. arr[i]

arr[i] 表示当前索引 i 对应的数值在 nums 数组中出现的次数。

4. ((index + 1) % 2 + arr[i])

这一步是把 (index + 1) % 2 和 arr[i] 的值加起来:

  • 如果当前是奇数个元素 ((index + 1) % 2 = 1),那么结果就是 1 + arr[i]

  • 如果当前是偶数个元素 ((index + 1) % 2 = 0),那么结果就是 0 + arr[i]

这相当于调整了 arr[i] 的数值,使得某些条件下它多加 1 或不变,这和计算中位数的位置有关系。

5. / 2

这一步是对整个表达式进行除以 2:

  • 如果 arr[i] 是偶数或者 (index + 1) % 2 是 0,那么 (index + 1) % 2 + arr[i] 是偶数,除以 2 后返回一个整数。

  • 如果 arr[i] 是奇数,并且 (index + 1) % 2 = 1,这会使得奇数变为偶数的一半。

总体意义

这个表达式的作用在于,在遍历过程中,根据当前遍历的元素顺序(index)以及该元素的出现次数(arr[i]),判断要不要取一半的数值(除以 2),这样就可以控制贡献给 res 的数值。在处理中位数相关的算法时,这个操作可以帮助判断中位数所在位置以及应取多少值。

举例

假设:

  • arr[i] = 3 表示当前这个数出现了 3 次,

  • index + 1 = 5 表示当前是第 5 个元素,

那么:

  • (index + 1) % 2 = 1,所以 ((index + 1) % 2 + arr[i]) = 1 + 3 = 4

  • / 2 后结果是 2,表示将当前的数值贡献 2 次。

这个操作对中位数或者其他与位置相关的统计操作有帮助。

class Solution {
    public int arrayPairSum(int[] nums) {
        if (nums.length <= 1800) {
            Arrays.sort(nums);
            int sum = 0;
            for (int i = 0; i < nums.length; i = i + 2) {
                sum = sum + nums[i];
            }
            return sum;
        } else {
            // 在该用数组排序的时候又把这件事忘了个干净
            int[] arr = new int[20001];
            for (int i = 0; i < nums.length; i++) {
                arr[nums[i] + 10000]++;
            }
            int index = 0;
            int res = 0;
            for (int i = 0; i < arr.length; i++) {
                if (arr[i] > 0) {
                    res = res + ((index + 1) % 2 + arr[i]) / 2 * (i - 10000);
                    index = index + arr[i];
                }
            }
            return res;
        }
    }
}

455. 分发饼干(简单)

假设你是一位很棒的家长,想要给你的孩子们一些小饼干。但是,每个孩子最多只能给一块饼干。

对每个孩子 i,都有一个胃口值 g[i],这是能让孩子们满足胃口的饼干的最小尺寸;并且每块饼干 j,都有一个尺寸 s[j] 。如果 s[j] >= g[i],我们可以将这个饼干 j 分配给孩子 i ,这个孩子会得到满足。你的目标是满足尽可能多的孩子,并输出这个最大数值。

解法一、排序+双指针

先排序。如果饼干比当前孩子胃口值小,那么饼干值往后挑。否则,i++,j++,计入结果。

class Solution {
    public int findContentChildren(int[] g, int[] s) {
        int i = 0,j = 0,res = 0;
        Arrays.sort(g);
        Arrays.sort(s);
        while(i < g.length && j < s.length){
            while(i < g.length && j < s.length && s[j] < g[i])j++;
            if(i < g.length && j < s.length && s[j] >= g[i]){
                i++;
                j++;
                res++;
            }
        }
        return res;
    }
}

稍微改善一些(2ms)的情况。在这次的循环里,以孩子都吃到为前提条件,如果饼干用完,则结束,减少了反复判断。

 public int findContentChildren0(int[] g, int[] s) {
            Arrays.sort(g);
            Arrays.sort(s);
            int result = 0;
            int j = 0;
            for (int i = 0; i < g.length; i++) {
                while (j < s.length && g[i] > s[j]) {
                    j++;
                }
                if (j >= s.length) {
                    break;
                }
                j++;
                result++;
            }
            return result;
        }

575. 分糖果(简单) 

Alice 有 n 枚糖,其中第 i 枚糖的类型为 candyType[i] 。Alice 注意到她的体重正在增长,所以前去拜访了一位医生。

医生建议 Alice 要少摄入糖分,只吃掉她所有糖的 n / 2 即可(n 是一个偶数)。Alice 非常喜欢这些糖,她想要在遵循医生建议的情况下,尽可能吃到最多不同种类的糖。

给你一个长度为 n 的整数数组 candyType ,返回: Alice 在仅吃掉 n / 2 枚糖的情况下,可以吃到糖的 最多种类数

解法一、枚举

只要品种不同就过,如果达到满值就break 

class Solution {
    public int distributeCandies(int[] candyType) {
        int res = 0,n2 = candyType.length;
        Arrays.sort(candyType);
        for(int i = 0;i < n2;i++){
            if(res == n2/2)return n2/2;
            res++;
            while(i < n2-1 && candyType[i]==candyType[i+1])i++;
        }
        return res;
    }
}

解法二、数据结构去重

 本质上就是统计种类,然后返回Math.min(n/2,m)的东西,只要能够统计种类,什么方法都可以。

class Solution {
    public int distributeCandies(int[] candyType) {
        Set<Integer> set = new HashSet<Integer>();
        for (int candy : candyType) {
            set.add(candy);
        }
        return Math.min(set.size(), candyType.length / 2);
    }
}

作者:力扣官方题解
链接:https://leetcode.cn/problems/distribute-candies/solutions/1072396/fen-tang-guo-by-leetcode-solution-l4f6/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

碎碎念

  • 605需要转换思维,121、122是一个系列,考察dp还蛮有意思的。其中122的贪心做法比其他想法都要简单。感觉贪心里目前用到排序的次数很多

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

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

相关文章

千行百业用AI大模型,为什么火山引擎是聚处?

“角儿是座儿叫出来的”&#xff0c;这句话不仅适合相声艺术&#xff0c;也很符合AI大模型商业化的现状。 今年以来&#xff0c;“大模型落地”成为AI和云产业的高频词。避免“叫好不叫座”&#xff0c;让AI大模型更快地融入行业场景之中&#xff0c;被各行各业真正用起来&…

CSS之我不会

一、选择器 作用&#xff1a;选择页面上的某一个后者某一类元素 基本选择器 1.标签选择器 格式&#xff1a;标签{} <h1>666</h1><style>h1{css语法} </style>2.类选择器 格式&#xff1a;.类名{} <h1 class"name">666</h1>…

uniapp组件知识记录

style标签的lang <template><view class"content"><h1 class"test"><span class"test1">我</span></h1>是谁</view> </template><style lang"scss">.content {// content中允…

基于Java+SpringBoot+Vue+MySQL的高校物品捐赠管理系统

作者&#xff1a;计算机学姐 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、JSP、ElementUI等&#xff0c;“文末源码”。 专栏推荐&#xff1a;前后端分离项目源码、SpringBoot项目源码、SSM项目源码 系统展示 基于SpringBootVue的高校物品捐赠管理系统【附源码文档】、…

数据结构代码集训day17(适合考研、自学、期末和专升本)

习题来自B站up&#xff1a;白话拆解数据结构 今日习题如下&#xff1a; 1、写出二叉树的前、中、后序遍历 2、写出二叉树的非递归前序和中序遍历 二叉树有多种存储结构&#xff1a;双亲存储法、孩子兄弟链存储结构&#xff0c;二叉链表存储结构等&#xff0c;一般我们写代码题…

如何实现一个定时任务?六种策略可实现

目录标题 1、自定义单线程2、JDK ScheduledExecutorService3、 Spring Task4、Quartz5、Elastic-job6、xxl-job最后&#xff1a;思考更上一层1. 高性能2. 高并发3. 高可用 设计方案 1、自定义单线程 上图中&#xff0c;我们启动一个线程&#xff0c;该线程无限循环执行&#xf…

STM32高级定时器生成互补PWM的原理与代码实现

文章目录 前言一 CubeMx配置1.1 TIM1 Mode and Configuration1.2 Paramter Settings 二 程序代码三 仿真分析总结 前言 互补 PWM&#xff08;Complementary PWM&#xff09;是指一对逻辑状态互为反相的 PWM&#xff08;脉冲宽度调制&#xff09;信号。这种信号配置常见于电机控…

SQL进阶技巧:如何利用SQL解决趣味赛马问题?| 非等值关联匹配问题

目录 0 问题描述 1 数据准备 2 问题分析 方法一:先分后合思想 方法2:非等值关联匹配 3 小结 0 问题描述 有一张赛马记录表,如下所示: create table RacingResults ( trace_id char(3) not null,race_date date not null, race_nbr int not null,win_name char(30) n…

探索 Redis Set:命令、编码与应用实践

set 类型 一 . 常见命令1.1 sadd、smembers1.2 sismember1.3 spop、srandmember1.4 smove1.5 srem1.6 集合间操作交集 : sinter、sinterstore并集 : sunion、sunionstore差集 : sdiff、sdiffstore 小结 二 . 内部编码6.3 应用场景6.3.1 使用 Set 来保存用户的标签6.3.2 使用 Se…

android kotlin基础复习 enum

1、kotlin中&#xff0c;关键字enum来定义枚举类型。枚举类型可以包含多个枚举常量&#xff0c;并且每个枚举常量可以有自己的属性和方法。 2、测试代码&#xff1a; enum class Color{RED,YELLOW,BLACK,GOLD,BLUE,GREEN,WHITE }inline fun <reified T : Enum<T>>…

Qt工程实践_06_Qt MSVC2O17编译器下的程序添加VS2017生成的动态链接库方法

文章目录 1. 利用VS2017生成动态链接库1.1 创建C++空项目1.2 添加.h和.cpp内容:添加了一个减法运算1.3 设置动态链接库目标计算机类型1.4 设置项目属性为动态库1.5 生成项目,复制需要的文件2. Qt程序使用VS2017生成的动态链接库方法2.1 创建Widget程序2.2 链接动态库文件2.2.…

蚂蚁SEO|AI养站程序是什么|蚂蚁蜘蛛池

《AI 养站程序&#xff1a;开启网站运营新未来》 在当今数字化时代&#xff0c;网站运营的重要性日益凸显。而 AI 养站程序的出现&#xff0c;为网站运营者带来了全新的机遇与挑战。 一、什么是 AI 养站程序 AI 养站程序是利用人工智能技术&#xff0c;对网站进行自动化管理和优…

MacBook air pro验机流程

由于苹果电脑价格相对较高&#xff0c;用户在网上购置之后&#xff0c;最好对机器要进行一下验机&#xff0c;以确保自己所购置的机器为原厂正品一手机。此外&#xff0c;在网上购置时&#xff0c;注意开相应的发票&#xff0c;方便后续的保修和换机等其他流程。 本文主要是介绍…

中小学生学籍照片(390×480蓝底)手机拍照制作流程说明

近期各地中小学陆续开学&#xff0c;幼升小及小升初一年级新生一般要在十月份之前完成学籍档案采集&#xff0c;其中就包括了新生学籍证件照的采集&#xff08;即学籍照片&#xff09;&#xff0c;部分中部省份使用的学籍照片像素尺寸为390&#xff08;宽&#xff09;480&#…

[C#学习笔记]注释

官方文档&#xff1a;Documentation comments - C# language specification | Microsoft Learn 一、常用标记总结 1.1 将文本设置为代码风格的字体&#xff1a;<c> 1.2 源代码或程序输出:<code> 1.3 异常指示:<exception> 1.4 段落 <para> 1.5 换行&…

Vue+Element多套主题切换

Vue3.x Element Plus与Vue2.x Element ui多套主题的切换方案 demo地址 VueElement更换主题: Vue Element项目&#xff0c;更换几套主题的方案 思路很简单&#xff0c;就是写好每套样式&#xff0c;写个切换功能&#xff0c;切换主题即可 具体实现方案&#xff1a; 准备多…

物联网技术推动灌区智能化管理

物联网技术&#xff0c;作为信息技术革命的重要组成部分&#xff0c;正深刻地改变着传统行业的运作模式&#xff0c;其中在农业灌溉领域的应用尤为显著&#xff0c;为灌区的智能化管理开辟了新径。这一技术通过将传感器、智能网关、大数据分析与云平台紧密融合&#xff0c;实现…

What is Node.JS and its Pros and Cons

What is Node.JS and its Pros and Cons JavaScript is a client-side development tool. Node.js is a server-side development tool. And it’s only a runtime environment based on Chrome V8 so we don’t write some code in Node.js. Pros: JavaScript on a server …

TypeScript 在 Vue.js 中的应用指南

在前端开发中&#xff0c;TypeScript 和 Vue.js 的组合越来越受到青睐。TypeScript 的强类型系统和 Vue.js 的组件化架构相得益彰&#xff0c;可以帮助你编写更可靠和易维护的代码。如果你已经掌握了 TypeScript 的基本语法&#xff0c;但不太确定怎么将它与 Vue.js 配合使用&a…

opencv 实现两个图片的拼接去重功能

基础知识介绍 cv::Mat 是OpenCV库中用来表示图像和矩阵数据的核心类之一。它是一个多维数组&#xff0c;可以存储图像像素数据、矩阵数据以及其他类型的数据。以下是关于 cv::Mat 类的一些详细解释&#xff1a; 构造函数&#xff1a;cv::Mat 类有多个构造函数&#xff0c;可以用…