• 【数组】优美的排列 II


    题目描述

    给你两个整数 n 和 k ,请你构造一个答案列表 answer ,该列表应当包含从 1 到 n 的 n 个不同正整数,并同时满足下述条件:

    假设该列表是 answer = [a1, a2, a3, ... , an] ,那么列表 [|a1 - a2|, |a2 - a3|, |a3 - a4|, ... , |an-1 - an|] 中应该有且仅有 k 个不同整数。
    返回列表 answer 。如果存在多种答案,只需返回其中 任意一种 。

    示例 1:

    输入:n = 3, k = 1
    输出:[1, 2, 3]
    解释:[1, 2, 3] 包含 3 个范围在 1-3 的不同整数,并且 [1, 1] 中有且仅有 1 个不同整数:1

    解题思路

    这道题实际是一道数学题目,找数学规律;下面就是分析这个题目的过程:

    假设n=4,分别求解k=[1,2,3]的answer列表:

    假设n=5,分别求解k=[1,2,3,4]的answer列表:

    根据这个规律可以有下面的思路:

    • 准备2个list,分别是l1和l2;
    • 计算分割时需要的数字长度:move=k/2;
    • l1记录从1到n-move的数字,l2记录从n到n-move+1的数字;
    • 判断是l1的数字作为第一个,还是l2的数字作为第一个;判断逻辑如下:boolean isLeftFirst = k % 2 == 1;
    • 开始merge操作,将结果merge到 int res[] = new int[n]中;
    • 返回res。

    代码实现如下:

    1. import java.util.ArrayList;
    2. import java.util.Arrays;
    3. import java.util.List;
    4. class Solution1 {
    5. public int[] constructArray(int n, int k) {
    6. int move = k / 2;
    7. int left = 1;
    8. List l1 = new ArrayList<>(n - move);
    9. for (int i = left; i <= n - move; i++) {
    10. l1.add(i);
    11. }
    12. List l2 = new ArrayList<>(move);
    13. for (int i = n; i > n - move; i--) {
    14. l2.add(i);
    15. }
    16. int leftIndex = 0;
    17. int rightIndex = 0;
    18. int index = 0;
    19. int[] res = new int[n];
    20. boolean isLeftFirst = k % 2 == 1;
    21. while (leftIndex < l1.size() && rightIndex < l2.size()) {
    22. if (isLeftFirst) {
    23. res[index] = l1.get(leftIndex);
    24. index++;
    25. leftIndex++;
    26. res[index] = l2.get(rightIndex);
    27. index++;
    28. rightIndex++;
    29. } else {
    30. res[index] = l2.get(rightIndex);
    31. index++;
    32. rightIndex++;
    33. res[index] = l1.get(leftIndex);
    34. index++;
    35. leftIndex++;
    36. }
    37. }
    38. while (leftIndex < l1.size()) {
    39. res[index] = l1.get(leftIndex);
    40. index++;
    41. leftIndex++;
    42. }
    43. while (rightIndex < l2.size()) {
    44. res[index] = l2.get(rightIndex);
    45. index++;
    46. rightIndex++;
    47. }
    48. return res;
    49. }
    50. public static void main(String[] args) {
    51. Solution1 solution = new Solution1();
    52. System.out.println(Arrays.toString(solution.constructArray(4, 1)));
    53. System.out.println(Arrays.toString(solution.constructArray(4, 2)));
    54. System.out.println(Arrays.toString(solution.constructArray(4, 3)));
    55. System.out.println(Arrays.toString(solution.constructArray(5, 1)));
    56. System.out.println(Arrays.toString(solution.constructArray(5, 2)));
    57. System.out.println(Arrays.toString(solution.constructArray(5, 3)));
    58. System.out.println(Arrays.toString(solution.constructArray(5, 4)));
    59. }
    60. }

    按照上述思路,能够解决问题,但是耗时方面还可以进一步优化;

    这里不再使用l1 和 l2 做list的合并,改成直接merge数组,int res[] = new int[n]; 按照这个思路改写完成后代码如下:

    1. import java.util.Arrays;
    2. class Solution {
    3. public int[] constructArray(int n, int k) {
    4. int move = k / 2;
    5. boolean isLeftFirst = k % 2 == 1;
    6. int left = 1;
    7. int right = n;
    8. int countIndex = 0;
    9. int[] newRes = new int[n];
    10. while (countIndex < n) {
    11. if (isLeftFirst) {
    12. if (left <= n - move) {
    13. newRes[countIndex] = left;
    14. left++;
    15. countIndex++;
    16. }
    17. if (right > n - move) {
    18. newRes[countIndex] = right;
    19. right--;
    20. countIndex++;
    21. }
    22. } else {
    23. if (right > n - move) {
    24. newRes[countIndex] = right;
    25. right--;
    26. countIndex++;
    27. }
    28. if (left <= n - move) {
    29. newRes[countIndex] = left;
    30. left++;
    31. countIndex++;
    32. }
    33. }
    34. }
    35. return newRes;
    36. }
    37. public static void main(String[] args) {
    38. Solution solution = new Solution();
    39. System.out.println(Arrays.toString(solution.constructArray(4, 1)));
    40. System.out.println(Arrays.toString(solution.constructArray(4, 2)));
    41. System.out.println(Arrays.toString(solution.constructArray(4, 3)));
    42. System.out.println(Arrays.toString(solution.constructArray(5, 1)));
    43. System.out.println(Arrays.toString(solution.constructArray(5, 2)));
    44. System.out.println(Arrays.toString(solution.constructArray(5, 3)));
    45. System.out.println(Arrays.toString(solution.constructArray(5, 4)));
    46. }
    47. }

     这道题优化结果如下:

    总结

    最近做这些题目发现都是找数学规律,找到数学规律后再做代码实现,最后是做代码耗时优化,后续可以多看看数学相关的书籍。

     

     

  • 相关阅读:
    Jmeter接口自动化(七)后置处理器
    使用Nginx进行负载均衡
    gtest从一无所知到熟练运用(1)gtest安装
    MySQL事务基本操作(方式2)
    Oracle数据库Bug:相关子查询多层嵌套报错:标识符无效
    imitation learning
    kubelet节点压力驱逐
    “理解梯度下降:直觉、数学公式和推导”
    centos 7.9离线安装wget
    LeetCode-148. Sort List [C++][Java]
  • 原文地址:https://blog.csdn.net/weiliuhong1/article/details/126773404