• 【数组】最大相等频率


    题目描述

    给你一个正整数数组nums,请你帮忙从该数组中找出能满足下面要求的最长前缀,并返回该前缀的长度:

    从前缀中恰好删除一个元素后,剩下每个数字的出现次数都相同。
    如果删除这个元素后没有剩余元素存在,仍可认为每个数字都具有相同的出现次数(也就是0次)。

    示例1:

    输入:nums=[2,2,1,1,5,3,3,5]
    输出:7
    解释:对于长度为7的子数组[2,2,1,1,5,3,3],如果我们从中删去nums[4]=5,就可以得到[2,2,1,1,3,3],里面每个数字都出现了两次。

    解题思路

    这道题就是找到一个从0到x到数组,这个数组满足:删除一个元素后其他元素个数相等。

    针对:nums=[2,2,1,1,5,3,3,5],思路如下:

    • 统计每个元素的出现次数,2->2次、1->2次、5->2次、3->2次;
    • 从右到左开始遍历数组
      • 不删除元素,2->2次、1->2次、5->2次、3->2次;不满足条件。
      • 删除最后一个元素5,2->2次、1->2次、5->1次、3->2次;由于 元素5 只出现一次,所以再把出现一次的5删除后得到:2->2次、1->2次、3->2次;所以满足条件返回结果[2,2,1,1,5,3,3]的长度:7.

    这道题最复杂的是考虑所有可能的情况:

    1. 所有元素出现频次都是1,那么一定满足条件;
    2. 如果只有一个元素出现频次是1,其他频次都相等;那么删除出现频次是1的元素后,其他频次都相等,这个满足条件;
    3. 如果只有一个元素出现频次最大该频次是n,其他元素频次相等都是为m;如果m+1==n,那么满足条件。

    代码实现

    1. import java.util.*;
    2. class Solution {
    3. public int maxEqualFreq(int[] nums) {
    4. Map map = new HashMap<>();
    5. for (int i = 0; i < nums.length; i++) {
    6. int value = map.getOrDefault(nums[i], 0);
    7. map.put(nums[i], ++value);
    8. }
    9. // 如果只有一个数字直接返回
    10. if (map.size() == 1) {
    11. return nums.length;
    12. }
    13. if (check(null, map)) {
    14. return nums.length;
    15. }
    16. for (int i = nums.length; i > 0; i--) {
    17. if (check(nums[i - 1], map)) {
    18. return i - 1;
    19. }
    20. }
    21. return 1;
    22. }
    23. private boolean check(Integer num, Map map) {
    24. if (num != null) {
    25. int v = map.get(num);
    26. --v;
    27. if (v > 0) {
    28. map.put(num, v);
    29. } else {
    30. map.remove(num);
    31. }
    32. }
    33. List list = new ArrayList<>();
    34. Set set = new HashSet<>();
    35. for (int value : map.values()) {
    36. if (!set.contains(value)) {
    37. set.add(value);
    38. }
    39. list.add(value);
    40. }
    41. Collections.sort(list);
    42. if (set.size() == 1 && list.get(0) == 1) {
    43. return true;
    44. } else if (set.size() == 2) {
    45. int minCount = 0;
    46. int maxCount = 0;
    47. for (int value : list) {
    48. if (value == list.get(0)) {
    49. minCount++;
    50. } else {
    51. maxCount++;
    52. }
    53. }
    54. return minCount == 1 && list.get(0) == 1 || maxCount == 1 && list.get(0) + 1 == list.get(list.size() - 1);
    55. } else {
    56. return false;
    57. }
    58. }
    59. public static void main(String[] args) {
    60. Solution solution = new Solution();
    61. System.out.println(solution.maxEqualFreq(new int[]{2, 2, 1, 1, 5, 3, 3, 5}));
    62. System.out.println(solution.maxEqualFreq(new int[]{2, 1, 1, 1, 1, 3, 1, 1}));
    63. System.out.println(solution.maxEqualFreq(new int[]{2, 1, 3, 1, 1, 3, 1, 2}));
    64. System.out.println(solution.maxEqualFreq(new int[]{1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5}));
    65. System.out.println(solution.maxEqualFreq(new int[]{1, 1, 1, 2, 2, 2, 3, 3, 3}));
    66. System.out.println(solution.maxEqualFreq(new int[]{1, 1, 1, 2, 2, 2}));
    67. }
    68. }

    这里对上面的代码进行一次优化,不使用MAP换用数组,并且最大值和最小值也不用SORT,代码改造后效果:

    1. import java.util.*;
    2. class Solution {
    3. //1 <= nums[i] <= 10 5
    4. public int maxEqualFreq(int[] nums) {
    5. int max = 0;
    6. for (int num : nums) {
    7. max = Math.max(num, max);
    8. }
    9. int[] map = new int[max + 1];
    10. for (int i = 0; i < nums.length; i++) {
    11. map[(nums[i])]++;
    12. }
    13. int count = 0;
    14. for (int v : map) {
    15. if (v != 0) {
    16. count++;
    17. }
    18. }
    19. if (count == 1) {
    20. return nums.length;
    21. }
    22. if (check(null, map)) {
    23. return nums.length;
    24. }
    25. for (int i = nums.length; i > 0; i--) {
    26. if (check(nums[i - 1], map)) {
    27. return i - 1;
    28. }
    29. }
    30. return 1;
    31. }
    32. private boolean check(Integer num, int[] map) {
    33. if (num != null) {
    34. map[(num)]--;
    35. }
    36. Set set = new HashSet<>();
    37. int min = Integer.MAX_VALUE;
    38. int minCount = 0;
    39. int max = Integer.MIN_VALUE;
    40. int maxCount = 0;
    41. for (int value : map) {
    42. if (value == 0) {
    43. continue;
    44. }
    45. if (!set.contains(value)) {
    46. set.add(value);
    47. }
    48. if (min > value) {
    49. min = value;
    50. minCount = 0;
    51. }
    52. if (min == value) {
    53. minCount++;
    54. }
    55. if (max < value) {
    56. max = value;
    57. maxCount = 0;
    58. }
    59. if (max == value) {
    60. maxCount++;
    61. }
    62. }
    63. if (set.size() == 1 && min == 1) {
    64. return true;
    65. } else if (set.size() == 2) {
    66. return minCount == 1 && min == 1 || maxCount == 1 && min + 1 == max;
    67. } else {
    68. return false;
    69. }
    70. }
    71. public static void main(String[] args) {
    72. Solution solution = new Solution();
    73. System.out.println(solution.maxEqualFreq(new int[]{100000, 100000}));
    74. System.out.println(solution.maxEqualFreq(new int[]{2, 2, 1, 1, 5, 3, 3, 5}));
    75. System.out.println(solution.maxEqualFreq(new int[]{2, 1, 1, 1, 1, 3, 1, 1}));
    76. System.out.println(solution.maxEqualFreq(new int[]{2, 1, 3, 1, 1, 3, 1, 2}));
    77. System.out.println(solution.maxEqualFreq(new int[]{1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5}));
    78. System.out.println(solution.maxEqualFreq(new int[]{1, 1, 1, 2, 2, 2, 3, 3, 3}));
    79. System.out.println(solution.maxEqualFreq(new int[]{1, 1, 1, 2, 2, 2}));
    80. }
    81. }

    总结

    这道题我主要时间都在做验证,很多case都要覆盖,整个严谨性还需要提高;欢迎有更快、更简洁的思路回复。

  • 相关阅读:
    MySQL迁移数据目录(2022.11.01)
    thinkphp5.1 单元测试phpunit使用和常见问题
    【智能指针】
    pymoo包NSGA2算法实现多目标遗传算法调参详细说明
    [分布式]-Raft论文研读
    接口的安全设计的几大要素:ticket,签名,时间戳
    基于FPGA的电子万年历设计
    初识C++多态
    4.3 x64dbg 搜索内存可利用指令
    cf:C. The Third Problem【关于排列这件事】
  • 原文地址:https://blog.csdn.net/weiliuhong1/article/details/126414433