4.4 贪心 排序

This commit is contained in:
zhangsan 2025-04-04 12:05:49 +08:00
parent 03761c6e10
commit d28142efa1
9 changed files with 340 additions and 3 deletions

View File

@ -0,0 +1,34 @@
package greedy;
import java.util.Arrays;
/**
* 题目 455. 分发饼干 (maxProfit)
* 描述给定一个数组 prices 它的第 i 个元素 prices[i] 表示一支给定股票第 i 天的价格
* 你只能选择 某一天 买入这只股票并选择在 未来的某一个不同的日子 卖出该股票设计一个算法来计算你所能获取的最大利润
* 返回你可以从这笔交易中获取的最大利润如果你不能获取任何利润返回 0
* 示例 1
输入: g = [1,2,3], s = [1,1]
输出: 1
解释:你有三个孩子和两块小饼干3 个孩子的胃口值分别是1,2,3
虽然你有两块小饼干由于他们的尺寸都是 1你只能让胃口值是 1 的孩子满足
所以你应该输出 1
* 链接https://leetcode.cn/problems/assign-cookies/
*/
public class FindContentChildren {
public int findContentChildren(int[] g, int[] s) {
int i=0,j=0,cnt=0;
Arrays.sort(g);
Arrays.sort(s);
while (i<g.length&&j<s.length){
if(g[i]<=s[j]) {
cnt++;
i++;
}
j++;
}
return cnt;
}
}

View File

@ -0,0 +1,36 @@
package greedy;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* 题目 121. 买卖股票的最佳时机 (maxProfit)
* 描述给定一个数组 prices 它的第 i 个元素 prices[i] 表示一支给定股票第 i 天的价格
* 你只能选择 某一天 买入这只股票并选择在 未来的某一个不同的日子 卖出该股票设计一个算法来计算你所能获取的最大利润
* 返回你可以从这笔交易中获取的最大利润如果你不能获取任何利润返回 0
* 示例 1
输入[7,1,5,3,6,4]
输出5
解释在第 2 股票价格 = 1的时候买入在第 5 股票价格 = 6的时候卖出最大利润 = 6-1 = 5
注意利润不能是 7-1 = 6, 因为卖出价格需要大于买入价格同时你不能在买入前卖出股票
* 链接https://leetcode.cn/problems/best-time-to-buy-and-sell-stock/
*/
//第一道贪心学思路
//每次都假设是今天卖出然后求今天之前的历史最低点
public class MaxProfit {
public int maxProfit(int prices[]) {
int minprice = Integer.MAX_VALUE;
int maxprofit = 0;
for (int price : prices) {
if (price < minprice) {
minprice = price;
} else if (price - minprice > maxprofit) {
maxprofit = price - minprice;
}
}
return maxprofit;
}
}

View File

@ -0,0 +1,45 @@
package greedy;
/**
* 题目 376. 摆动序列 (wiggleMaxLength)
* 描述如果连续数字之间的差严格地在正数和负数之间交替则数字序列称为 摆动序列 第一个差如果存在的话可能是正数或负数仅有一个元素或者含两个不等元素的序列也视作摆动序列
* 例如 [1, 7, 4, 9, 2, 5] 是一个 摆动序列 因为差值 (6, -3, 5, -7, 3) 是正负交替出现的
* 相反[1, 4, 7, 2, 5] [1, 7, 4, 5, 5] 不是摆动序列第一个序列是因为它的前两个差值都是正数第二个序列是因为它的最后一个差值为零
* 子序列 可以通过从原始序列中删除一些也可以不删除元素来获得剩下的元素保持其原始顺序
* 给你一个整数数组 nums 返回 nums 中作为 摆动序列 最长子序列的长度
* 示例 1
输入nums = [1,7,4,9,2,5]
输出6
解释整个序列均为摆动序列各元素之间的差值为 (6, -3, 5, -7, 3)
示例 2
输入nums = [1,17,5,10,13,15,10,5,16,8]
输出7
解释这个序列包含几个长度为 7 摆动序列
其中一个是 [1, 17, 10, 13, 10, 16, 8] 各元素之间的差值为 (16, -7, 3, -3, 6, -8)
* 链接https://leetcode.cn/problems/wiggle-subsequence/
*/
//不会 https://programmercarl.com/0376.%E6%91%86%E5%8A%A8%E5%BA%8F%E5%88%97.html
public class WiggleMaxLength {
public int wiggleMaxLength(int[] nums) {
if (nums.length <= 1) {
return nums.length;
}
//当前差值
int curDiff = 0;
//上一个差值
int preDiff = 0;
int count = 1;
for (int i = 1; i < nums.length; i++) {
//得到当前差值
curDiff = nums[i] - nums[i - 1];
//如果当前差值和上一个差值为一正一负
//等于0的情况表示初始时的preDiff
if ((curDiff > 0 && preDiff <= 0) || (curDiff < 0 && preDiff >= 0)) {
count++;
preDiff = curDiff;
}
}
return count;
}
}

View File

@ -4,11 +4,11 @@ import java.util.Comparator;
import java.util.PriorityQueue;
/**
* 题目 215. 数组中的第K个最大元素 (floodFill)
* 题目 215. 数组中的第K个最大元素 (findKthLargest)
* 描述给定整数数组 nums 和整数 k请返回数组中第 k 个最大的元素
* 请注意你需要找的是数组排序后的第 k 个最大的元素而不是第 k 个不同的元素
* 你必须设计并实现时间复杂度为 O(n) 的算法解决此问题
*
* 示例 1
输入: [3,2,1,5,6,4], k = 2
输出: 5
@ -28,7 +28,7 @@ public class FindKthLargest {
return maxheap.peek();
}
//使用最小堆来存储前 k 个最大的元素堆顶元素是 k 个最大元素中的最小值这样堆的大小始终保持为 k当堆的大小大于 k 弹出堆顶元素最终堆顶元素就是第 k 大的元素不需要完全填满堆再删除元素
public int findKthLargest(int[] nums, int k) {
public int findKthLargest2(int[] nums, int k) {
// 使用最小堆
PriorityQueue<Integer> minHeap = new PriorityQueue<>();
@ -47,4 +47,43 @@ public class FindKthLargest {
// 返回堆顶元素即为第 k 大的元素
return minHeap.peek();
}
//快速选择
public int quickselect(int[] nums, int l, int r, int k) {
// 当区间内只有一个元素时直接返回该元素
if (l >= r) {
return nums[l];
}
// 选取区间第一个元素作为枢轴
int pivot = nums[l];
int i = l, j = r;
// 分区过程调整数组使得左侧的元素不大于枢轴右侧的元素不小于枢轴
while (i < j) {
// 从右边向左扫描找到第一个小于 pivot 的元素放到左侧
while (i < j && nums[j] >= pivot) {
j--;
}
nums[i] = nums[j];
// 从左边向右扫描找到第一个大于 pivot 的元素放到右侧
while (i < j && nums[i] <= pivot) {
i++;
}
nums[j] = nums[i];
}
// 将枢轴放入正确的位置
nums[i] = pivot;
// 现在 i 即为枢轴位置
if (i == k) {
return nums[i];
} else if (k < i) {
return quickselect(nums, l, i - 1, k);
} else {
return quickselect(nums, i + 1, r, k);
}
}
public int findKthLargest(int[] _nums, int k) {
int n = _nums.length;
return quickselect(_nums, 0, n - 1, n - k);
}
}

View File

@ -0,0 +1,40 @@
package heap;
import java.util.HashMap;
import java.util.Map;
import java.util.PriorityQueue;
/**
* 题目 347. K 个高频元素 (topKFrequent)
* 描述给你一个整数数组 nums 和一个整数 k 请你返回其中出现频率前 k 高的元素你可以按 任意顺序 返回答案
* 示例 1
输入: nums = [1,1,1,2,2,3], k = 2
输出: [1,2]
* 链接https://leetcode.cn/problems/top-k-frequent-elements/
*/
public class TopKFrequent {
public int[] topKFrequent(int[] nums, int k) {
HashMap<Integer,Integer>map=new HashMap<>();
PriorityQueue<int[]> minHeap = new PriorityQueue<>(
(a, b) -> b[1] - a[1]);
int[] res=new int[k];
int i=0;
for (int num : nums) {
if(!map.containsKey(num))
map.put(num,1);
else
map.put(num,map.get(num)+1);
}
for (Map.Entry<Integer, Integer> entry : map.entrySet()) {
minHeap.add(new int[]{entry.getKey(),entry.getValue()});
}
while (!minHeap.isEmpty()) {
if(i<k)
res[i++] = minHeap.poll()[0];
else break;
}
return res;
}
}

View File

@ -0,0 +1,26 @@
package sort;
public class BubbleSort {
public void bubbleSort(int[] arr){
//n-1 趟冒泡
for (int i = 0; i < arr.length-1; i++) {
boolean flag=false;
//冒泡
for (int j = arr.length-1; j >i ; j--) {
if (arr[j-1]>arr[j]){
swap(arr,j-1,j);
flag=true;
}
}
//本趟遍历后没有发生交换说明表已经有序
if (!flag){
return;
}
}
}
private void swap(int[] arr,int i,int j){
int temp=arr[i];
arr[i]=arr[j];
arr[j]=temp;
}
}

View File

@ -0,0 +1,56 @@
package sort;
import java.util.Arrays;
public class MergeSort {
/**
* 归并排序入口函数
* @param arr 待排序数组
*/
public static void mergeSort(int[] arr) {
if (arr == null || arr.length <= 1) {
return; // 边界条件
}
int[] temp = new int[arr.length]; // 辅助数组
mergeSort(arr, 0, arr.length - 1, temp);
}
private static void mergeSort(int[] arr, int left, int right, int[] temp) {
if (left < right) {
int mid = (right + left) / 2;
mergeSort(arr, left, mid, temp); // 递归左子数组
mergeSort(arr, mid + 1, right, temp); // 递归右子数组
merge(arr, left, mid, right, temp); // 合并两个有序子数组
}
}
private static void merge(int[] arr, int left, int mid, int right, int[] temp) {
int i = left; // 左子数组起始指针
int j = mid + 1; // 右子数组起始指针
int t = 0; // 辅助数组指针
// 1. 按序合并两个子数组到temp
while (i <= mid && j <= right) {
if (arr[i] <= arr[j]) { // 注意等号保证稳定性
temp[t++] = arr[i++];
} else {
temp[t++] = arr[j++];
}
}
// 2. 将剩余元素拷贝到temp
while (i <= mid) {
temp[t++] = arr[i++];
}
while (j <= right) {
temp[t++] = arr[j++];
}
// 3. 将temp中的数据复制回原数组
t = 0;
while (left <= right) {
arr[left++] = temp[t++];
}
}
}

View File

@ -0,0 +1,46 @@
package sort;
public class QuickSort {
// 交换数组中两个元素的位置
public void quickSort(int[] arr, int begin, int end) {
if (begin >= end) {
return;
}
//划分为满足上述条件的两个子表返回基准位置
int pos=partition(arr,begin,end);
//对两个子表进行递归排序
quickSort(arr, begin, pos - 1);
quickSort(arr, pos + 1, end);
}
//划分左右子序列返回基准位置
public int partition(int[] arr, int i, int j){
int temp = arr[i];
while (i < j) {
//在右边找到小于temp的放到左边
while (i < j && arr[j] >= temp) {
j--;
}
arr[i] = arr[j];
//在左边找到大或等于于temp的放到右边
while (i < j && arr[i] <= temp) {
i++;
}
arr[j] = arr[i];
}
//将temp放在剩下的基准位置ij均可
arr[i] = temp;
return i;
}
public static void main(String[] args) {
int[] arr = {49, 38, 65, 97, 76, 13, 27, 49};
QuickSort solution = new QuickSort();
solution.quickSort(arr, 0, arr.length - 1);
System.out.println("\n排序后:");
for (int num : arr) {
System.out.print(num + " ");
}
}
}

View File

@ -0,0 +1,15 @@
package greedy;
import org.junit.Test;
import static org.junit.Assert.*;
public class FindContentChildrenTest {
@Test
public void findContentChildren() {
int[] g = {1,2,3}, s = {1,1};
FindContentChildren solution = new FindContentChildren();
int res=solution.findContentChildren(g,s);
}
}