本篇博客旨在整理记录自己刷的一些基础题的思路、代码以及注解,同时希望可给小伙伴一些帮助。本人也是算法小白,水平有限,如果文章中有什么错误之处,希望小伙伴们可以在评论区指出来,共勉 。
文章目录
- 贪心算法
- 1005.K次取反后最大化的数组和
- 1323. 6 和 9 组成的最大数字
- 1217. 玩筹码
- 942. 增减字符串匹配
- 605. 种花问题
- 860. 柠檬水找零
- 最后
贪心算法
1005.K次取反后最大化的数组和
难度:简单
题目
:给你一个整数数组 nums
和一个整数 k
,按以下方法修改该数组:
- 选择某个下标
i
并将nums[i]
替换为-nums[i]
。
重复这个过程恰好 k
次。可以多次选择同一个下标 i
。
以这种方式修改数组后,返回数组 可能的最大和 。
提示:
- 1 <= nums.length <= 104
-100 <= nums[i] <= 100
- 1 <= k <= 104
示例 1:
输入:nums = [4,2,3], k = 1输出:5解释:选择下标 1 ,nums 变为 [4,-2,3] 。
示例 2:
输入:nums = [3,-1,0,2], k = 3输出:6解释:选择下标 (1, 2, 2) ,nums 变为 [3,1,0,2] 。
示例 3:
输入:nums = [2,-3,-1,5,-4], k = 2输出:13解释:选择下标 (1, 4) ,nums 变为 [2,3,-1,5,4] 。
解题代码:
class Solution { public int largestSumAfterKNegations(int[] nums, int k) { //先排序 Arrays.sort(nums); int i=0,ans=0,n=nums.length; //给数组中的负数从小到大取反 while(k>0&&i<n&&nums[i]<0) { nums[i]=-nums[i++]; k--; } //k=0的话,数组已经达到取反最大数组和 //k>0,说明nums已经全是非负数,剩余取反只要反复操作最小数即可,且次数为奇数才会发生变化 if(k>0&&k%2==1){ //i==0说明nums原本就是非负数,最小数为nums[i] //0<i<n,说明数组中原先就有非负数,此时最小数为nums[i]和最后一个取反的负数nums[i-1]的较小数 //i=n,,说明数组原先全为负数,取反后最小数为最后一个取反负数,即nums[i-1] if(i==0||(i<n&&nums[i-1]>nums[i])) nums[i]=-nums[i]; else nums[i-1]=-nums[i-1]; } //求和 for(int num:nums) ans+=num; return ans; }}
1323. 6 和 9 组成的最大数字
难度:简单
题目
:给你一个仅由数字 6 和 9 组成的正整数 num
。
你最多只能翻转一位数字,将 6 变成 9,或者把 9 变成 6 。
请返回你可以得到的最大数字。
提示:
1 <= num <= 10^4
num
每一位上的数字都是 6 或者 9 。
示例 1:
输入:num = 9669输出:9969解释:改变第一位数字可以得到 6669 。改变第二位数字可以得到 9969 。改变第三位数字可以得到 9699 。改变第四位数字可以得到 9666 。其中最大的数字是 9969 。
示例 2:
输入:num = 9996输出:9999解释:将最后一位从 6 变到 9,其结果 9999 是最大的数。
示例 3:
输入:num = 9999输出:9999解释:无需改变就已经是最大的数字了。
思路:
输入6和9,反转6和9只能反转一个,要求组成最大数字,所以直接把最高位的6转换为9,就是最大数字。
首先将数字转换为字符串再转换为字符数组;
然后从左到右遍历,判断为6转换为9,输出即可结束!
解题代码:
class Solution { public int maximum69Number (int num) { String s = Integer.toString(num); char[] ch = s.toCharArray(); for(int i = 0;i < ch.length;i++){ if(ch[i] == '6'){ ch[i] = '9'; break; } } return Integer.parseInt(new String(ch)); }}
1217. 玩筹码
难度:简单
题目
:有 n
个筹码。第 i
个筹码的位置是 position[i]
。
我们需要把所有筹码移到同一个位置。在一步中,我们可以将第 i
个筹码的位置从 position[i]
改变为:
position[i] + 2
或position[i] - 2
,此时cost = 0
position[i] + 1
或position[i] - 1
,此时cost = 1
返回将所有筹码移动到同一位置上所需要的 最小代价 。
提示:
1 <= position.length <= 100
1 <= position[i] <= 10^9
示例 1:
输入:position = [1,2,3]输出:1解释:第一步:将位置3的筹码移动到位置1,成本为0。第二步:将位置2的筹码移动到位置1,成本= 1。总成本是1。
示例 2:
输入:position = [2,2,2,3,3]输出:2解释:我们可以把位置3的两个筹码移到位置2。每一步的成本为1。总成本= 2。
示例 3:
输入:position = [1,1000000000]输出:1
思路:
把所有的筹码移到同一位置,移动奇数位(+1/-1)代价为1,移动偶数位(+2/-2)代价为0;
遍历数组中的所有值,统计所有筹码位置(数组)的奇偶值;
返回奇数或偶数的最小值。
(当奇数位置上少,就直接全部移动到偶数位,所付出的代价就为奇数值;反之代价就为偶数值)
解题代码:
class Solution { public int minCostToMoveChips(int[] position) { int even = 0;//单数位 int add = 0;//双数位 for (int i = 0; i < position.length; i++) { if((position[i] % 2) != 0){ even++; }else{ add++; } } return Math.min(even,add); }}
942. 增减字符串匹配
难度:简单
题目
:由范围 [0,n]
内所有整数组成的 n + 1
个整数的排列序列可以表示为长度为 n
的字符串 s
,其中:
- 如果
perm[i] < perm[i + 1]
,那么s[i] == 'I'
- 如果
perm[i] > perm[i + 1]
,那么s[i] == 'D'
给定一个字符串 s
,重构排列 perm
并返回它。如果有多个有效排列perm,则返回其中 任何一个 。
提示:
1 <= s.length <= 105
s
只包含字符"I"
或"D"
示例 1:
输入:s = "IDID"输出:[0,4,1,3,2]
示例 2:
输入:s = "III"输出:[0,1,2,3]
示例 3:
输入:s = "DDI"输出:[3,2,0,1]
思路:
从题意上来看,对字符串进行遍历,需输出一个整数排序后的数组
字符串中只有‘I’或‘D’,遇‘I’数开始从0自增,遇‘D’后从字符串的长度开始依次递减;所以整数数组长度为字符串长度+1.
遇到‘I’就是赋值剩余的最小值;遇到‘D’就是赋值剩余的最大值。
解题代码:
class Solution { public int[] diStringMatch(String s) { int[] arr = new int[s.length()+1]; int left = 0,rigth = s.length(); for(int i = 0;i < s.length();++i){ if(s.charAt(i) == 'D'){ arr[i] = rigth; rigth--; }else{ arr[i] = left; left++; } } arr[s.length()] = left; return arr; }}
605. 种花问题
难度:简单
题目
:假设有一个很长的花坛,一部分地块种植了花,另一部分却没有。可是,花不能种植在相邻的地块上,它们会争夺水源,两者都会死去。
给你一个整数数组 flowerbed
表示花坛,由若干 0
和 1
组成,其中 0
表示没种植花,1
表示种植了花。另有一个数 n
,能否在不打破种植规则的情况下种入 n
朵花?能则返回 true
,不能则返回 false
。
提示:
1 <= flowerbed.length <= 2 * 10^4
flowerbed[i] 为 0 或 1
flowerbed 中不存在相邻的两朵花
0 <= n <= flowerbed.length
示例 1:
输入:flowerbed = [1,0,0,0,1], n = 1输出:true
示例 2:
输入:flowerbed = [1,0,0,0,1], n = 2输出:false
思路:
体现出来的贪心就在:应该在不打破种植规则的情况下种入尽可能多的花,然后判断可以种入的花的最多数量是否大于或等于n。
先对整个flowerbed进行遍历,遍历结束就停止。
① 判断如果当前位置已种植,则i+2位置可种植,因flowebed中不能出现两个相邻的花朵;
② 如果遍历到的元素下标i恰好为length-1,因为flowebed不能有相邻的花朵,所以说明这个位置是可以直接种花。或者判断i + 1是否为未种植的位置;可以进行种植,同时可直接(i+=2;)找到下一个未种植的位置。
③ 若当前位置(为0)不能种植(有相邻的花朵),直接使用i += 3;找到未种植位置
如果n已全部种植完就返回true,反之就为false。
解题代码:
class Solution { public boolean canPlaceFlowers(int[] flowerbed, int n) { for (int i = 0,len = flowerbed.length; i < len && n > 0;) { if(flowerbed[i] == 1){ i += 2; } else if(i == flowerbed.length - 1 || flowerbed[i + 1] == 0){ n--; //种植完后,同时可以找出下一个可以种植的位置 i += 2; }else{ i+=3; } } //n朵全部种完 return n <= 0; }}
860. 柠檬水找零
难度:简单
题目
:在柠檬水摊上,每一杯柠檬水的售价为 5
美元。顾客排队购买你的产品,(按账单 bills
支付的顺序)一次购买一杯。
每位顾客只买一杯柠檬水,然后向你付 5
美元、10
美元或 20
美元。你必须给每个顾客正确找零,也就是说净交易是每位顾客向你支付 5
美元。
注意,一开始你手头没有任何零钱。
给你一个整数数组 bills
,其中 bills[i]
是第 i
位顾客付的账。如果你能给每位顾客正确找零,返回 true
,否则返回 false
。
提示:
1 <= bills.length <= 10^5
bills[i]
不是5
就是10
或是20
示例 1:
输入:bills = [5,5,5,10,20]输出:true解释:前 3 位顾客那里,我们按顺序收取 3 张 5 美元的钞票。第 4 位顾客那里,我们收取一张 10 美元的钞票,并返还 5 美元。第 5 位顾客那里,我们找还一张 10 美元的钞票和一张 5 美元的钞票。由于所有客户都得到了正确的找零,所以我们输出 true。
示例 2:
输入:bills = [5,5,10,10,20]输出:false解释:前 2 位顾客那里,我们按顺序收取 2 张 5 美元的钞票。对于接下来的 2 位顾客,我们收取一张 10 美元的钞票,然后返还 5 美元。对于最后一位顾客,我们无法退回 15 美元,因为我们现在只有两张 10 美元的钞票。由于不是每位顾客都得到了正确的找零,所以答案是 false。
思路:
贪心也就主要体现在优先考虑10元面额的优先支出,毕竟五元面额可用性多
1、找零面额分为5元和10元或20元;当他们支付一个5元面额,找零金额可以直接递增;
2、当支付10面额时无5元面额,则导致无法找零,就返回false,否则就五元面额递减,10元面额递增;
3、当支付面额大于10元时,只有20元;所以找零时直接5元面额减去一张,10元面额减去一张;当无10元面额时且5元面额大于3时,直接5元面额减去三张就行。反之就返回false;
解题代码:
class Solution { public boolean lemonadeChange(int[] bills) { int five = 0,ten = 0;//定义五元和十元的找零面额 for (int bill:bills) { if (bill == 5){ five++; } else if(bill == 10){ if(five == 0) { return false; } five--; ten++; }else{ if(five > 0 && ten > 0){ five--; ten--; }else if(five >= 3){ five -= 3; }else{ return false; } } } return true; }}
最后
建议结合力扣一起刷题,有帮助的话,希望可以点赞❤️+收藏⭐,谢谢各位大佬~~