(笔试算法题)Leetcode101之贪心算法


题目都是Leetcode上,是基于谷歌大佬整理的题目,可以在github上搜索Leetcode101.

1.分配问题

455. 分发饼干–简单

给定一堆饼干和一群孩子,求这些饼干可以使得多少个孩子吃饱,每个孩子只能吃一块饼干。

Input: [1,2], [1,2,3]
Output: 2
第一个数组表示孩子的饥饿度,第二个数组表示饼干的大小,这里只需要把大小为 [1,2] 的饼干分给饥饿度为[1,2]的孩子即可。
/**
	思路:优先让最小的饼干,满足饥饿度最小的孩子。
**/
class Solution {
    public int findContentChildren(int[] g, int[] s) {
        Arrays.sort(g);
        Arrays.sort(s);
        int child = 0, cookie = 0;
        while (child < g.length && cookie < s.length) {
            if (g[child] <= s[cookie]) child++;
            cookie++;
        }
        return child;
    }
}

135. 分发糖果–困难

n个站成一排的孩子,每个孩子有一个评分,相邻孩子中评分高的比其相邻孩子的糖果更多,求如何分配使得分发糖果最少。(每个孩子最少一颗糖果)

输入:ratings = [1,0,2]
输出:5
分配: 2 1 2, 即给评分0的孩子分配一个,其余孩子分配2个
/**
	思路:两次遍历,从左往右和从右往左遍历,如果评分高,则在其相邻孩子的基础上+1
**/
class Solution {
    public int candy(int[] ratings) {
        int size = ratings.length;
        int[] value = new int[size];
        Arrays.fill(value, 1);
        for (int i = 1; i < ratings.length; i++) {
            if (ratings[i] > ratings[i-1]) {
                value[i] = value[i-1] + 1;
            }
        }
        for (int i = ratings.length-2; i >= 0; i--) {
            if (ratings[i] > ratings[i+1]) {
                if (value[i] < (value[i+1] + 1))
                    value[i] = value[i+1] + 1;
            }
        }
        return Arrays.stream(value).sum();
    }
}

435. 无重叠区间–中等

给定一个区间集,求移除最少的区间使得区间互相不重合。(边界相等不算重合)

输入: intervals = [[1,2],[2,3],[3,4],[1,3]]
输出: 1
移除 [1,3] 区间,使得剩余区间不重合
/**
	思路:按照区间右端点升序排序,右端点越小,其留出的空间越大。
**/
class Solution {
    public int eraseOverlapIntervals(int[][] intervals) {
        Arrays.sort(intervals, (e1,e2) -> e1[1] - e2[1]);
        int count = 0;
        int right = intervals[0][1];
        for (int i = 1; i < intervals.length; i++) {
            if (intervals[i][0] >= right) {
                right = intervals[i][1];
            } else {
                count++;
            }
        }
        return count;
    }
}

/**
	动态规划思路:会超时。 
    	类似于最长递增子序列, dp[i] = Math.max(dp[i], dp[j] + 1); 如果i可以放在j之后
**/
class Solution {
    public int eraseOverlapIntervals(int[][] intervals) {
    	Arrays.sort(intervals, (e1, e2) -> {return e1[0] - e2[0];});
    	int[] dp = new int[intervals.length];
    	Arrays.fill(dp, 1);
    	for (int i = 1; i < intervals.length; ++i) {
    		for (int j = 0; j < i; ++j) {
    			if (intervals[i][0] >= intervals[j][1]) dp[i] = Math.max(dp[i], dp[j] + 1);
    		}
    	}
    	return intervals.length - Arrays.stream(dp).max().getAsInt();
    }
}

605. 种花问题–简单

给定一个01串,0表示可以种花,1表示已被占用了,要求相邻两块空地不能同时种花,判断给定花朵数是否可种植。

输入:flowerbed = [1,0,0,0,1], n = 1
输出:true
可以在中间的0种花。
/**
	思路:计算给定的花园能种几棵花,然后判断其与目标的大小。
	处理边界:0的左为0 和 flowerbed.length-1 的右为0
**/
class Solution {
    public boolean canPlaceFlowers(int[] flowerbed, int n) {
    	int sum = 0;
    	for (int i = 0; i < flowerbed.length; ++i) {
    		if (flowerbed[i] == 1) continue;
    		int l = i==0?0:flowerbed[i-1];
    		int r = (i==flowerbed.length-1)?0:flowerbed[i+1];
    		if(l == 0 && r == 0) {
    			flowerbed[i] = 1;
    			++sum;
    		}
    	}
    	return sum >= n;
    }
}

452. 用最少数量的箭引爆气球–中等

给定一些气球的左右边界,一只箭可以垂直x方向射出,求用最少的箭扎破所有气球(擦边也算)。

输入:points = [[10,16],[2,8],[1,6],[7,12]]
输出:2
在 x=6 x=11处,用两个箭即可
/**
	思路: 按照气球右端点升序排序。
    	第一个气球(即:最小的右端点必然需要一个气球),如果后面存在与之交集,则可以通过一个气球解决。
	Integer.compare(e1[1], e2[1]);   // 处理可能越界问题
**/
class Solution {
    public int findMinArrowShots(int[][] points) {
    	Arrays.sort(points, (e1, e2) -> {
    		return Integer.compare(e1[1], e2[1]);
    	});
    	int sum = 1, right = points[0][1];
    	for (int i = 1; i < points.length; ++i) {
    		if (points[i][0] <= right) continue;
    		++sum;
    		right = points[i][1];
    	}
    	return sum;
    }
}

在这里插入图片描述

763. 划分字母区间–中等

一个字符串划分成尽可能多的片段,使得相同字母出现在同一片段中,返回每个片段长度。

输入:S = "ababcbacadefegdehijhklij"
输出:[9,7,8]
划分结果为:"ababcbaca", "defegde", "hijhklij"
/**
	思路:在遍历前,记录每个字符的最后一次出现位置。
    	遍历时,start记录每个片段的开始,end记录开始到遍历之间所有字符的最后一次出现位置,
    	如果 i == end,说明 (start, end)之间包含了里面的字母,在其区间外面不包含。
**/
class Solution {
    public List<Integer> partitionLabels(String s) {
    	List<Integer> res = new ArrayList<>();
    	Map<Character, Integer> map = new HashMap<>();
    	for (int i = 0; i < s.length(); ++i) map.put(s.charAt(i), i);
    	int start = 0, end = map.get(s.charAt(0));
    	for (int i = 0; i < s.length(); ++i) {
    		char cur = s.charAt(i);
            end = Math.max(end, map.get(cur));
    		if (i < end) continue;
    		res.add(end - start + 1);
    		start = i + 1;
    	}
    	return res;
    }
}

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

每次可以买卖一只股票,且每次只能持有一只股票,求如何买卖获得的利润最大。

输入:prices = [7,1,5,3,6,4]
输出:7
	第2天买,第3天卖 利润 5-1=4		第4天买第5天卖  6-3=3     总利润  4+3=7
/**
	思路:贪心
    	只要涨了,就加上该利润。
**/
class Solution {
    public int maxProfit(int[] prices) {
    	int profit = 0;
    	for (int i = 1; i < prices.length; ++i) {
    		if (prices[i] > prices[i-1]) profit += prices[i] - prices[i-1];
    	}
    	return profit;
    }
}

/**
	思路:动态规划
    	dp[i][0]: 表示当前有一只股票
    	dp[i][1]: 表示当前没有股票
    	那么 初始 dp[i][0] = -prices[0];
**/
class Solution {
    public int maxProfit(int[] prices) {
        int[][] dp = new int[prices.length + 1][2];
    	dp[1][0] = -prices[0];
    	for (int i = 1; i < prices.length; ++i) {
            int cur = i+1;
    		dp[cur][0] = Math.max(dp[i][0], dp[i][1] - prices[i]);
    		dp[cur][1] = Math.max(dp[i][1], dp[i][0] + prices[i]);
    	}
    	return dp[prices.length][1];
    }
}

406. 根据身高重建队列–中等

给定一个二维数组,其中 p e o p l e [ i ] [ 0 ] people[i][0] people[i][0]表示第i个人身高, p e o p l e [ i ] [ 1 ] people[i][1] people[i][1]表示他前面应该有几个人身高大于等于他,返回构建后的队列。

输入:people = [[7,0],[4,4],[7,1],[5,0],[6,1],[5,2]]
输出:[[5,0],[7,0],[5,2],[6,1],[4,4],[7,1]]
/**	两种思路图示:如下图
	思路:先降排,后插入。
    	按照身高降序,按照位序升序。
    	也就是说 [7,0] 在 [7,1] 之前。
**/
class Solution {
    public int[][] reconstructQueue(int[][] people) {
    	Arrays.sort(people, (e1, e2) -> {
    		if(e1[0] != e2[0]) return e2[0] - e1[0];
    		else return e1[1] - e2[1];
    	});

    	List<int[]> res = new ArrayList<>();
    	for (int i = 0; i < people.length; ++i) {
    		res.add(people[i][1], people[i]);
    	}
    	return res.toArray(new int[people.length][2]);
    }
}

/**
	思路2:先升序,后插入
**/
class Solution {
    public int[][] reconstructQueue(int[][] people) {
    	Arrays.sort(people, (e1, e2) -> {
    		if (e1[0] != e2[0]) return e1[0] - e2[0];
    		else return e2[1] - e1[1];
    	});
    	
    	int[][] res = new int[people.length][];
    	for (int i = 0; i < people.length; ++i) {
    		int spaces = people[i][1] + 1;
    		for (int j = 0; j < people.length; ++j) {
    			if (res[j] == null) {
    				--spaces;
    				if (spaces == 0) {
    					res[j] = people[i];
    					break;
    				}
    			}
    		}
    	}
    	return res;
    }
}

在这里插入图片描述

665. 非递减数列–中等

判断是否修改数组中的值,不超过一次,使得数组单调不减。

输入: nums = [4,2,3]
输出: true
修改 4 -> 1 数组递增
/**
	分析: 
    	存在以下两种情况:可以修改一次得到单调不减的序列
        	1. [1 6 4 7]		可以通过修改6 变成 1 2 4 7 序列
        	2. [5 6 4 7]		可以修改 4 变成 5 6 6 7 序列
    	结论 第一种情况是 4 > 1 可以修改一次 (即: 修改6)
        	 第2中情况是 6 < 7 修改一次 (即:修改4)
    	当出现递减序列不满足这两种情况,则至少需要两次修改操作。
**/
class Solution {
    public boolean checkPossibility(int[] nums) {
    	int cnt = 0;
    	for (int i = 1; i < nums.length; ++i) {
    		if(nums[i] >= nums[i-1]) continue;
    		int l = i==1?0:nums[i-2];
            int r = i==nums.length-1?(1<<20):nums[i+1];
    		if (nums[i] >= l) ++cnt;
            else if (nums[i-1] <= r) ++cnt;
    		else return false;
    	}
    	return cnt <= 1;
    }
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值