贪心算法或贪心思想采用贪心的策略,保证每次操作都是局部最优的,从而使最后得到的结果是全局最优的。
贪心从某种意义上来讲,它不是一种算法,是一种思维,真正解决问题的是贪心思维加上其它的算法(排序、手动模拟、数据结构、搜索等),下面即将开启贪心的学习,并配合几套题目的练习。
分发饼干(简单)(排序+贪心)
把饼干和小孩的胃口值分别升序排序,用较小尺寸的饼干去满足较小胃口值的小孩。
import java.util.Arrays;
class Solution {
public int findContentChildren(int[] g, int[] s) {
Arrays.sort(g);
Arrays.sort(s);
int res = 0;
int i = 0, j = 0;
while (i < g.length && j < s.length) {
if (g[i] <= s[j]) {
res++;
i++;
j++;
}else {
j++;
continue;
}
}
return res;
}
}
分发糖果(困难)(贪心)
这道题还是没搞明白为什么,先把题解放着吧。
代码:
class Solution {
public int candy(int[] ratings) {
int n = ratings.length;
int[] left = new int[n];
for (int i = 0; i < n; i++) {
if (i > 0 && ratings[i] > ratings[i - 1]) {
left[i] = left[i - 1] + 1;
} else {
left[i] = 1;
}
}
int right = 0, ret = 0;
for (int i = n - 1; i >= 0; i--) {
if (i < n - 1 && ratings[i] > ratings[i + 1]) {
right++;
} else {
right = 1;
}
ret += Math.max(left[i], right);
}
return ret;
}
}
最长回文串(简单)
注意区分大小写,一看到回文题目要知道回文串里的每个字符,最多只有一个字符出现奇数次,其余都是偶数次。
class Solution {
public int longestPalindrome(String s) {
// 先统计已有字符串中的字符个数(区分大小写)
int[] hash = new int[128];
for(int i = 0; i < s.length(); i++) {
hash[s.charAt(i)]++;
}
// 统计最长回文长度
int ans = 0;
// 注意回文串中最多有一个奇数字符(作为中间字符),其余字符都为偶数
for(int i = 0; i < 128; i++) {
// 整数除 2,不论奇偶个数字符都是取偶数个,乘 2是因为左右对称,各有一半
ans += (hash[i] / 2) * 2;
if (hash[i] % 2 == 1 && ans % 2 == 0) {
ans++;
}
}
return ans;
}
}
数组拆分Ⅰ(简单)
数组从小到大排序后,累加第1 3 5 7 …位数。
class Solution {
public int arrayPairSum(int[] nums) {
Arrays.sort(nums);
int ans = 0;
int i = 0;
while (i < nums.length) {
ans += nums[i];
i += 2;
}
return ans;
}
}
验证回文字符串Ⅱ(简单)
双指针一前一后遍历字符串,如果遇到不同的字符就试试去除前面的字符或后面的字符,去除后再判断是否为回文串。
class Solution {
public boolean validPalindrome(String s) {
int i = 0, j = s.length() - 1;
while (i < j) {
// i == j 时不用判断
if (s.charAt(i) == s.charAt(j)) {
i++;
j--;
}else {
return check(i+1, j, s) || check(i, j-1, s);
}
}
return true;
}
static boolean check(int i, int j, String s) {
while (i < j) {
if (s.charAt(i) == s.charAt(j)) {
i++;
j--;
}else {
return false;
}
}
return true;
}
}
柠檬水找零(简单)
在付20美元时,需要找回15美元,优先用10美元的去找,然后再用5美元,因为5美元的可用性更高。
class Solution {
public boolean lemonadeChange(int[] bills) {
int[] price = new int[30];
for (int i = 0; i < bills.length; i++) {
int tmp = bills[i];
if (tmp == 5) {
price[tmp]++;
}else if (tmp == 10) {
if (price[5] > 0) {
price[5]--;
price[tmp]++;
}else {
return false;
}
}else {
// tmp == 20,先用10块钱的去找零,5块钱更灵动
if (price[10] >= 1 && price[5] >= 1) {
price[tmp]++;
price[10]--;
price[5]--;
}else if(price[5] >= 3) {
price[tmp]++;
price[5] -= 3;
}else {
return false;
}
}
}
return true;
}
}
看示例就能得到规律:I从0开始放,D从N开始放,最后判别最后一个字符是什么字符再确定数组最后一个元素。
class Solution {
public int[] diStringMatch(String s) {
int len = s.length();
// 仔细看示例就能看出规律
int left = 0;
int right = len;
int[] ans = new int[len + 1];
for (int i = 0; i < len; i++) {
if (s.charAt(i) == 'I') {
ans[i] = left;
left++;
}else {
ans[i] = right;
right--;
}
}
if (s.charAt(len - 1) == 'I') {
ans[len] = ans[len - 1] + 1;
}else {
ans[len] = ans[len - 1] - 1;
}
return ans;
}
}
将数组分成和相等的三个部分(简单)
整个数组的和应该能被3整除,每一部分是连续的。
class Solution {
public boolean canThreePartsEqualSum(int[] arr) {
// 整个数组的和必须要能被 3 整除
// 是连续的三个部分
int sum = 0;
for (int i = 0; i < arr.length; i++) {
sum += arr[i];
}
if (sum % 3 != 0) {
return false;
}
sum = sum / 3;
int cnt = 0;
int i = 0;
int tmp = 0;
while (i < arr.length) {
tmp += arr[i];
if (tmp == sum) {
cnt++;
tmp = 0;
}
if (cnt == 3) {
return true;
}
i++;
}
return false;
}
}
玩筹码(简单)
偶数位置可以0代价放到位置0,奇数位置可以0代价放到位置1,再比较0、1筹码个数,把个数少的移到多的身上去,代价为筹码数 * 1。
class Solution {
public int minCostToMoveChips(int[] position) {
// 偶数位置筹码都放到 第 0 个位置
// 奇数位置筹码都放到 第 1 个位置(因为左右移2个单位,代价为 0 )
int z = 0;
int f = 0;
// 注意position记录一个个筹码的位置
for (int i = 0; i < position.length; i++) {
if (position[i] % 2 == 0) {
z++;
} else {
f++;
}
}
return z > f ? f : z;
}
}
分割平衡字符串(简单)
维护一个变量cnt,遇到R就加1,遇到L就减1,如果cnt=0说明有字符串成立了,答案+1。(重要的是贪心的思维、思路,代码实现都很简单)
class Solution {
public int balancedStringSplit(String s) {
int cnt = 0;
int all = 0;
for (int i = 0; i < s.length(); i++) {
if (s.charAt(i) == 'R') {
cnt++;
}else {
cnt--;
}
if (cnt == 0) {
all++;
}
}
return all;
}
}