查找数组第K大数字
题意:
查找一个数字第k大数字,如数组a={1,2,3,4,5,6} ,它的第2大数字就是5
代码
快排思路解决:
/**
* 在一个数组查找最k大数字
*/
public static int findKthLargestNum(int[] nums, int k) {
return quickSelect(nums, 0, nums.length - 1, nums.length-k);
}
private static int quickSelect(int[] nums, int l, int r, int index) {
int q = randomPartion(nums, l, r);
if (q == index) {
return nums[index];
} else {
return q < index ? quickSelect(nums, q + 1, index,r) : quickSelect(nums, l, q - 1, index);
}
}
public static int randomPartion(int[] arr, int left, int right) {
//以数组的第一位作为比较基准值
int key = arr[left];
//循环遍历,直到left和right重合
while (left < right) {
//从后向前遍历,直到找到比key值小的数停止
while (left < right && arr[right] >= key) {
right--;
}
//将找到的数赋值给left角标
arr[left] = arr[right];
//从前向后遍历,直到找到比key值大的数停止
while (left < right && arr[left] <= key) {
left++;
}
//将找到的数赋值给此时的right角标
arr[right] = arr[left];
}
//此时left位是空缺的,将key值赋值给left
arr[left] = key;
return left;
}
private static void swap(int[] nums, int i, int r) {
int temp = nums[r];
nums[r] = nums[i];
nums[i] = temp;
}
public static void main(String[] args) {
int[] a = {47, 36, 64, 12, 45, 5};
int value = findKthLargestNum(a, 1);
System.out.println(value);
}
附加快排算法实现:
/**
* 快排
*
* @param arr
* @param left
* @param right
*/
public static void quickSortArr_bak(int[] arr, int left, int right) {
if (left < right) {
int pivot = partition(arr, left, right);
quickSortArr_bak(arr, left, pivot - 1);
quickSortArr_bak(arr, pivot + 1, right);
}
}
/**
* 将数组分成两部分,pivot之前的数都比key小,之后的都比key大
*
* @param arr
* @param left
* @param right
* @return pivot 中轴角标
*/
public static int partition(int[] arr, int left, int right) {
//以数组的第一位作为比较基准值
int key = arr[left];
//循环遍历,直到left和right重合
while (left < right) {
//从后向前遍历,直到找到比key值小的数停止
while (left < right && arr[right] >= key) {
right--;
}
//将找到的数赋值给left角标
arr[left] = arr[right];
//从前向后遍历,直到找到比key值大的数停止
while (left < right && arr[left] <= key) {
left++;
}
//将找到的数赋值给此时的right角标
arr[right] = arr[left];
}
//此时left位是空缺的,将key值赋值给left
arr[left] = key;
return left;
}
public static void main(String args[]) {
int[] a = {47, 36, 64, 12, 45, 5};
quickSortArr_bak(a, 0, a.length - 1);
for (int i=0;i<a.length;i++){
System.out.println(a[i]);
}
}
数组最长上升子序列
题意
给出一个整数数组,求数组的最长上升子序列,如数组a={22,23,12,34,23},该数据的最长上升子序列为{22,23,34}长度为3
代码
public static int maxProsingLength(int[] nums) {
int[] dp = new int[nums.length];
for (int i=0;i<nums.length;i++){
dp[i]=1;
}
int max = 0;
if (nums.length <= 1) {
return nums.length;
}
for (int i = 1; i < nums.length; i++) {
for (int j = 0; j < i; j++) {
if (nums[i] > nums[j]) {
dp[i] = Math.max(dp[i], dp[j] + 1);
}
}
max = Math.max(max, dp[i]);
}
return max;
}
public static void main(String[] args) {
int[] a = {47, 36, 64, 12, 45, 5};
int num = maxProsingLength(a);
System.out.println(num);
}
数组合并区间
题意:
以数组 intervals 表示若干 区间的集合,其中单个区间为 interval[i] = [starti,endi] 合并所有区间重叠的区间,并返回一个不重叠的区间,要求该区间要覆盖所有的区间
思路
对所有的区间进行starti开始时间进行排序,如果starti < startj && endi> startj 这表示两个区间存在重叠 (i<j),starti<startj && endi <startj 是不会重叠的
代码:
public static int[][] merge(int[][] nums) {
if (nums.length == 0) {
return new int[0][2];
}
Arrays.sort(nums, new Comparator<int[]>() {
@Override
public int compare(int[] o1, int[] o2) {
//比较开始时间 开始时间小的放前面
return o1[0] - o2[0];
}
});
List<int[]> list = new ArrayList<>();
for (int i = 0; i < nums.length; i++) {
int start = nums[i][0], end = nums[i][1];
//判断 后面的开始时间与前面的开始时间 结束时间是不重叠的
if (list.size() == 0 || list.get(list.size() - 1)[1] < start) {
list.add(nums[i]);
} else {
//存在重叠 和前面一个区间
int[] temp = list.get(list.size() - 1);
temp[1] = Math.max(end, temp[1]);
}
}
return list.toArray(new int[0][0]);
}
public static void main(String[] args) {
int [][]nums ={{12,34},{24,23},{27,39}};
int [][] list =merge(nums);
for (int i=0;i<list.length;i++){
System.out.println(list[i][0]+","+list[i][1]);
}
}
换零钱
题意
coins表示可换的零钱,money表示需要换的金钱数额
代码
/**
* dp 贪心计算
*
* @param coins
* @param money
* @return
*/
public static int minCoinChange(Integer[] coins, int money) {
int[] dp = new int[money + 1];
Arrays.fill(dp, money + 1);
dp[0] = 0;
for (int i = 1; i <= money; i++) {
for (int j = 0; j < coins.length; j++) {
if (coins[j] <= i) {
dp[i] = Math.min(dp[i], dp[i - coins[j]] + 1);
}
}
}
return dp[money] > money ? -1 : dp[money];
}
/**
* 遍历计算
*
* @param conis
* @param money
* @return
*/
public static int minCoinChange2(Integer[] conis, int money) {
Arrays.sort(conis, new Comparator<Integer>(){
@Override
public int compare(Integer o1, Integer o2) {
return o2-o1;
}
});
int count = 0;
for (int i = 0; i < conis.length; i++) {
while (conis[i] <= money) {
count += money / conis[i];
money = money % conis[i];
}
}
return count;
}
public static void main(String[] args) {
Integer[] coins = {1, 2, 5, 10};
System.out.println(minCoinChange(coins, 20));
System.out.println(minCoinChange2(coins, 20));
}
数组最长公共子数组
描述
最长重复子数组 这个是重复的数组 如 nums1={1, 22, 33, 44,55} 和nums2={22, 33, 11, 44,55}
两个数组的最长公共的数组是{22,33} 或者{44,55}所以长度是2
给定 两个整数数组 nums1 nums2 返回两个数组的公共相同的 长度最长的子数组的长度
代码
public static int findMaxCommonLength(int[] nums1, int[] nums2) {
int m = nums1.length;
int n = nums2.length;
int ans =0;
int [][]dp = new int[m+1][n+1];
for (int i= m-1;i>=0;i--){
for (int j= n-1;j>=0;j--){
dp[i][j]=nums1[i]==nums2[j]?dp[i+1][j+1]+1:0;
ans = Math.max(ans,dp[i][j]);
}
}
return ans;
}
基于滑动窗口 减少比较次数 将数组的两端对齐 分别比较
对齐有两种方式
第一类 数组1不同 数组2的首部和数组1的某个元素对齐
第一类 数组2不同 数组1的首部和数组2的某个元素对齐
public static int findMaxCommonLength2(int[] nums1, int[] nums2) {
int m = nums1.length;
int n = nums2.length;
int ans =0;
//nums2的某个元素和nums1的头部对齐
for (int i=0;i<m;i++){
int len = Math.min(n,m-i);
int maxLen= maxLength(nums1,nums2,i,0,len);
ans = Math.max(ans,maxLen);
}
for (int i=0;i<n;i++){
int len = Math.min(m,n-i);
int maxLen= maxLength(nums1,nums2,0,i,len);
ans = Math.max(ans,maxLen);
}
return ans;
}
数组版本的最长公共子序列
题意
数组的最长子序列 可以对比字符串的最长子序列,如 nums1={1, 22, 33, 44,55} 和nums2={22, 33, 11, 44,55} 子序列{22,33,44,55} 既是nums1的子序列也是nums2的子序列
代码
public static int subMaxCommonNumLength(int[] nums1, int[] nums2) {
int m = nums1.length;
int n = nums2.length;
int [][]dp = new int[m+1][n+1];
if(nums1.length ==0 || nums2.length==0){
return 0;
}
for (int i=1;i<=m;i++){
for (int j=1;j<=n;j++){
if(nums1[i-1]==nums2[j-1]){
dp[i][j]= dp[i-1][j-1]+1;
}else{
dp[i][j] = Math.max(dp[i-1][j],dp[i][j-1]);
}
}
}
return dp[m][n];
}