Letcode数组相关算法

这篇博客探讨了如何在数组中查找第K大数字,使用快排思想实现;同时介绍了求解数组最长上升子序列的方法;并展示了合并区间、找零钱和数组最长公共子数组的算法实现。这些内容涉及到了排序、动态规划和贪心策略等编程技巧。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

查找数组第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];
  }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序员路同学

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值