当前位置:  首页>> 技术小册>> 数据结构与算法(中)

难度:
Hard

题意:

  1. 求一个字符串中的所有非空子字符串,这些字符串当中的唯一字符数的总和
  2. 唯一字符数就是在字符串中出现只有一次的字符的个数

思路:

  • 枚举左右端点,暴力统计子字符串的唯一字符数,复杂度是o(n^3)
  • 枚举左端点,然后遍历右端点,每次保存上一次的字符统计个数,和唯一字符数,并更新为当前的数值,复杂度是o(n^2)
  • 注意到,当某个字符出现次数大于1个后,后面不管怎么遍历,该字符都不会是唯一字符,因此,有个剪枝动作,如果此时某个字符出现次数大于1个后,后面直接跳过该字符
  • 因此我们需要实现把每个字符出现的位置记录下来,以便可以跳过某些字符
  • 枚举左端点,然后遍历右端点,加上剪枝之后,每个字符至多被扫描2次。把字符串拆成26个字符后,从左边遍历到右边,就需要一个堆来维持,类似于归并排序的merge操作,这个堆最多26个元素,时间复杂度是o(52nlog26)
  • 我们可以另外想一种解决方案。假设我们把26个字母全部拆开,当某个字符第一次出现到第二次出现中间,它就能贡献一个唯一字符。假设A这个字符,第一次出现是位置1,第二次出现是位置10,于是1-10中间就可以增加一个唯一字符,同理,其他字符也是这样的。假设左端点移动,所需要改变的,也只有一个字符而已,这个字符的第一次出现的位置,到第二次出现的位置,改变了位置。我们不要想着每个字符串有多少唯一字符,而是从总体来看,每个字符贡献了多少次唯一字符。还是上面那个例子,A这个字符,第一次出现是位置1,第二次出现是位置10,那么贡献了10-1=9次唯一字符。扫描左端点时,只需要不断用上一个左端点字符移动来更新总唯一字符数即可。复杂度是o(n)

解法一:

  1. class Solution {
  2. private class Item implements Comparable<Item> {
  3. int alph;
  4. int idx;
  5. int pos;
  6. public Item(int alph, int idx, int pos) {
  7. this.alph = alph;
  8. this.idx = idx;
  9. this.pos = pos;
  10. }
  11. @Override
  12. public int compareTo(Item o) {
  13. return Integer.compare(pos, o.pos);
  14. }
  15. }
  16. private int solve(List[] idxList, int start, int len, int[] init) {
  17. PriorityQueue<Item> queue = new PriorityQueue<Item>();
  18. boolean[] flag = new boolean[26];
  19. for (int i = 0;i < 26;i++) {
  20. flag[i] = false;
  21. }
  22. int ret = 0;
  23. int res = 0;
  24. int pre = start - 1;
  25. for (int i = 0;i < 26;i++) {
  26. int idx = init[i];
  27. if (idx != idxList[i].size()) {
  28. queue.add(new Item(i, idx, (Integer) idxList[i].get(idx)));
  29. }
  30. }
  31. while (!queue.isEmpty()) {
  32. Item top = queue.poll();
  33. ret += (long) res * (top.pos - pre) % MOD;
  34. if (ret >= MOD) {
  35. ret -= MOD;
  36. }
  37. if (flag[top.alph]) {
  38. res--;
  39. } else {
  40. flag[top.alph] = true;
  41. if (top.idx + 1 != idxList[top.alph].size()) {
  42. queue.add(new Item(top.alph, top.idx + 1, (Integer) idxList[top.alph].get(top.idx + 1)));
  43. }
  44. res++;
  45. }
  46. pre = top.pos;
  47. }
  48. ret += (long) res * (len - pre) % MOD;
  49. if (ret >= MOD) {
  50. ret -= MOD;
  51. }
  52. return ret;
  53. }
  54. private static int MOD = 1000000007;
  55. public int uniqueLetterString(String S) {
  56. List[] idxList = new List[26];
  57. int[] init = new int[26];
  58. for (int i = 0;i < 26;i++) {
  59. idxList[i] = new ArrayList<Integer>();
  60. init[i] = 0;
  61. }
  62. for (int i = 0;i < S.length();i++) {
  63. idxList[S.charAt(i) - 'A'].add(i);
  64. }
  65. int ret = 0;
  66. for (int i = 0;i < S.length();i++) {
  67. ret += solve(idxList, i, S.length(), init);
  68. if (ret >= MOD) {
  69. ret -= MOD;
  70. }
  71. init[S.charAt(i) - 'A']++;
  72. }
  73. return ret;
  74. }
  75. }

解法二:

  1. class Solution {
  2. private static int MOD = 1000000007;
  3. public int uniqueLetterString(String S) {
  4. List<Integer>[] idxList = new List[26];
  5. int[] pos = new int[26];
  6. for (int i = 0;i < 26;i++) {
  7. idxList[i] = new ArrayList<Integer>();
  8. pos[i] = 0;
  9. }
  10. for (int i = 0;i < S.length();i++) {
  11. idxList[S.charAt(i) - 'A'].add(i);
  12. }
  13. int ret = 0;
  14. int res = 0;
  15. for (int i = 0;i < 26;i++) {
  16. if (pos[i] < idxList[i].size()) {
  17. if (pos[i] + 1 < idxList[i].size()) {
  18. res += idxList[i].get(pos[i] + 1) - idxList[i].get(pos[i]);
  19. } else {
  20. res += S.length() - idxList[i].get(pos[i]);
  21. }
  22. }
  23. }
  24. for (int i = 0;i < S.length();i++) {
  25. ret += res;
  26. if (ret >= MOD) {
  27. ret -= MOD;
  28. }
  29. int j = S.charAt(i) - 'A';
  30. if (pos[j] + 1 < idxList[j].size()) {
  31. res -= idxList[j].get(pos[j] + 1) - idxList[j].get(pos[j]);
  32. } else {
  33. res -= S.length() - idxList[j].get(pos[j]);
  34. }
  35. pos[j]++;
  36. if (pos[j] < idxList[j].size()) {
  37. if (pos[j] + 1 < idxList[j].size()) {
  38. res += idxList[j].get(pos[j] + 1) - idxList[j].get(pos[j]);
  39. } else {
  40. res += S.length() - idxList[j].get(pos[j]);
  41. }
  42. }
  43. }
  44. return ret;
  45. }
  46. }

该分类下的相关小册推荐: