编程合集: https://www.cnblogs.com/jssj/p/12002760.html

前言:不仅仅要实现,更要提升性能,精益求精,用尽量少的时间复杂度和空间复杂度解决问题。

【程序68】
将两个有序链表合并为一个新的有序链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。

  1. public class ListNode {
  2. int val;
  3. ListNode next;
  4. ListNode(){
  5.  
  6. }
  7. ListNode(int x) { val = x; }
  8. }
  1. /**
  2. * 将两个有序链表合并为一个新的有序链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。
  3. */
  4. public class Subject68 {
  5. public static void main(String[] args) {
  6. ListNode listNode0 = new ListNode(1);
  7. ListNode listNode1 = new ListNode(2);
  8. ListNode listNode2 = new ListNode(3);
  9. ListNode listNode3 = new ListNode(-9);
  10. ListNode listNode4 = new ListNode(3);
  11. listNode0.next = listNode1;
  12. listNode1.next = listNode2;
  13. listNode2.next = listNode3;
  14. listNode3.next = listNode4;
  15.  
  16. ListNode listNode01 = new ListNode(5);
  17. ListNode listNode11 = new ListNode(7);
  18. listNode01.next = listNode11;
  19.  
  20. ListNode tmp = mergeTwoLists(listNode3,listNode01);
  21. StringBuilder stringBuilder = null;
  22. while(tmp !=null){ //指向位置是否为空
  23. if(stringBuilder == null){
  24. stringBuilder = new StringBuilder();
  25. stringBuilder.append(tmp.val);
  26. }else{
  27. stringBuilder.append(" -> "+ tmp.val);
  28. }
  29. tmp = tmp.next; // 指向下一个节点
  30. }
  31. System.out.println(stringBuilder.toString());
  32. }
  33.  
  34. /**
  35. * 递归实现链表插入
  36. * @param l1
  37. * @param l2
  38. * @return
  39. */
  40. public static ListNode mergeTwoLists(ListNode l1, ListNode l2) {
  41. if (l1 == null) {
  42. return l2;
  43. }
  44. else if (l2 == null) {
  45. return l1;
  46. }
  47. else if (l1.val < l2.val) {
  48. l1.next = mergeTwoLists(l1.next, l2);
  49. return l1;
  50. }
  51. else {
  52. l2.next = mergeTwoLists(l1, l2.next);
  53. return l2;
  54. }
  55. }
  56. }

时间复杂度:O(n+m)

运行结果:

【程序69】
给出 n 代表生成括号的对数,请你写出一个函数,使其能够生成所有可能的并且有效的括号组合。

  1. import java.util.ArrayList;
  2. import java.util.List;
  3.  
  4. /**
  5. * 给出 n 代表生成括号的对数,请你写出一个函数,使其能够生成所有可能的并且有效的括号组合。
  6. */
  7. public class Subject69 {
  8. public static void main(String[] args) {
  9. System.out.println(generateParenthesis(4));
  10. }
  11.  
  12. /**
  13. * 递归解题
  14. * @param n
  15. * @return
  16. */
  17. public static List<String> generateParenthesis(int n) {
  18. if(n == 1){
  19. List<String> list = new ArrayList<>();
  20. list.add("()");
  21. return list;
  22. }else{
  23. List<String> list = generateParenthesis(n-1);
  24. int sizes = list.size();
  25. List<String> newList = new ArrayList<>();
  26. for (int i = 0; i < sizes; i++) {
  27. String tmp = list.get(i);
  28. char[] arr = tmp.toCharArray();
  29. for (int j = 0; j < arr.length; j++) {
  30. String tmp0 = tmp.substring(0,j);
  31. String tmp1 = tmp.substring(j,tmp.length());
  32. String tmp2 = tmp0 + "()" +tmp1;
  33. if(!newList.contains(tmp2)){
  34. newList.add(tmp2);
  35. }
  36. }
  37. }
  38. return newList;
  39. }
  40. }
  41. }

运行结果:

【程序70】
合并 k 个排序链表,返回合并后的排序链表。请分析和描述算法的复杂度。

  1. public class ListNode {
  2. int val;
  3. ListNode next;
  4. ListNode(){
  5.  
  6. }
  7. ListNode(int x) { val = x; }
  8. }
  1. /**
  2. * 合并 k 个排序链表,返回合并后的排序链表。请分析和描述算法的复杂度。
  3. */
  4. public class Subject70 {
  5. public static void main(String[] args) {
  6.  
  7. ListNode listNode0 = new ListNode(-10);
  8. ListNode listNode1 = new ListNode(-9);
  9. ListNode listNode2 = new ListNode(-9);
  10. ListNode listNode3 = new ListNode(-3);
  11. ListNode listNode4 = new ListNode(-1);
  12. ListNode listNode5 = new ListNode(-1);
  13. ListNode listNode6 = new ListNode(0);
  14.  
  15. listNode1.next = listNode0;
  16. listNode2.next = listNode1;
  17. listNode3.next = listNode2;
  18. listNode4.next = listNode3;
  19. listNode5.next = listNode4;
  20. listNode6.next = listNode5;
  21.  
  22. ListNode listNode01 = new ListNode(-5);
  23. ListNode listNode02 = new ListNode(4);
  24. ListNode listNode03 = new ListNode(-8);
  25.  
  26. ListNode listNode11 = null;
  27.  
  28. ListNode listNode20 = new ListNode(-9);
  29. ListNode listNode21 = new ListNode(-6);
  30. ListNode listNode22 = new ListNode(-5);
  31. ListNode listNode23 = new ListNode(-4);
  32. ListNode listNode24 = new ListNode(-2);
  33. ListNode listNode25 = new ListNode(2);
  34. ListNode listNode26 = new ListNode(3);
  35.  
  36. listNode21.next = listNode20;
  37. listNode22.next = listNode21;
  38. listNode23.next = listNode22;
  39. listNode24.next = listNode23;
  40. listNode25.next = listNode24;
  41. listNode26.next = listNode25;
  42.  
  43. ListNode listNode30 = new ListNode(-3);
  44. ListNode listNode31 = new ListNode(-3);
  45. ListNode listNode32 = new ListNode(-2);
  46. ListNode listNode33 = new ListNode(-1);
  47. ListNode listNode34 = new ListNode(0);
  48.  
  49. listNode31.next = listNode30;
  50. listNode32.next = listNode31;
  51. listNode33.next = listNode32;
  52. listNode34.next = listNode33;
  53.  
  54. ListNode[] arr = new ListNode[]{listNode6,listNode01,listNode02,listNode03,listNode11,listNode26,listNode34};
  55. ListNode tmp= mergeKLists(arr);
  56. StringBuilder stringBuilder = null;
  57. while(tmp !=null){ //指向位置是否为空
  58. if(stringBuilder == null){
  59. stringBuilder = new StringBuilder();
  60. stringBuilder.append(tmp.val);
  61. }else{
  62. stringBuilder.append(" -> "+ tmp.val);
  63. }
  64. tmp = tmp.next; // 指向下一个节点
  65. }
  66. System.out.println(stringBuilder.toString());
  67. }
  68.  
  69. /**
  70. * 合并链表
  71. * @param lists
  72. * @return
  73. */
  74. public static ListNode mergeKLists(ListNode[] lists) {
  75. if(lists.length == 0){
  76. return null;
  77. }
  78. ListNode[] arr = mergeKLists0(lists);
  79. return arr[0];
  80. }
  81.  
  82. /**
  83. * 使用合并算法,组合链表
  84. * @param lists
  85. * @return
  86. */
  87. public static ListNode[] mergeKLists0(ListNode[] lists) {
  88. int length = lists.length;
  89. if(length == 1){
  90. return lists;
  91. }
  92. ListNode[] listTmp = new ListNode[(int)Math.ceil(length/2.0)];
  93. ListNode[] listTmp0 = null;
  94. for (int i = 0 ,j = 0; i < length; i = i+2 , j++) {
  95. ListNode tmp0 = null;
  96. if(i+1 <= length-1){
  97. tmp0 = mergeTwoLists(lists[i],lists[i+1]);
  98. }else{
  99. tmp0 = mergeTwoLists(lists[i],null);
  100. }
  101. listTmp[j] = tmp0;
  102. }
  103. listTmp0 = mergeKLists0(listTmp);
  104. return listTmp0;
  105. }
  106.  
  107. /**
  108. * 递归实现链表插入
  109. * @param l1
  110. * @param l2
  111. * @return
  112. */
  113. public static ListNode mergeTwoLists(ListNode l1, ListNode l2) {
  114. if (l1 == null) {
  115. return l2;
  116. }
  117. else if (l2 == null) {
  118. return l1;
  119. }
  120. else if (l1.val < l2.val) {
  121. l1.next = mergeTwoLists(l1.next, l2);
  122. return l1;
  123. }
  124. else {
  125. l2.next = mergeTwoLists(l1, l2.next);
  126. return l2;
  127. }
  128. }
  129. }

时间复杂度:O(Nlogk)

运行结果:

【程序71】
给定一个链表,两两交换其中相邻的节点,并返回交换后的链表。

  1. public class ListNode {
  2. int val;
  3. ListNode next;
  4. ListNode(){
  5.  
  6. }
  7. ListNode(int x) { val = x; }
  8. }
  1. /**
  2. * 给定一个链表,两两交换其中相邻的节点,并返回交换后的链表。
  3. */
  4. public class Subject71 {
  5.  
  6. public static void main(String[] args) {
  7. ListNode listNode0 = new ListNode(1);
  8. ListNode listNode1 = new ListNode(2);
  9. ListNode listNode2 = new ListNode(3);
  10. ListNode listNode3 = new ListNode(-9);
  11. ListNode listNode4 = new ListNode(3);
  12. listNode0.next = listNode1;
  13. listNode1.next = listNode2;
  14. listNode2.next = listNode3;
  15. listNode3.next = listNode4;
  16. ListNode tmp = swapPairs(listNode0);
  17.  
  18. StringBuilder stringBuilder = null;
  19. while(tmp !=null){ //指向位置是否为空
  20. if(stringBuilder == null){
  21. stringBuilder = new StringBuilder();
  22. stringBuilder.append(tmp.val);
  23. }else{
  24. stringBuilder.append(" -> "+ tmp.val);
  25. }
  26. tmp = tmp.next; // 指向下一个节点
  27. }
  28. System.out.println(stringBuilder.toString());
  29. }
  30.  
  31. /**
  32. * 交换链表数据位置
  33. * @param head
  34. * @return
  35. */
  36. public static ListNode swapPairs(ListNode head) {
  37. ListNode newHead = new ListNode(0);
  38. ListNode resultHead = newHead;
  39. while(head != null){
  40. ListNode tmp0 = new ListNode(head.val);
  41. ListNode tmp1 = null;
  42. if(head.next != null){
  43. tmp1 = new ListNode(head.next.val);
  44. newHead.next = tmp1;
  45. tmp1.next = tmp0;
  46. head = head.next.next;
  47. }else{
  48. newHead.next = tmp0;
  49. head = null;
  50. }
  51. newHead = tmp0;
  52.  
  53. }
  54. return resultHead.next;
  55. }
  56. }

时间复杂度:O(n)

运行结果:

【程序72】
给定一个链表,两两交换其中相邻的节点,并返回交换后的链表。
给你一个链表,每k个节点一组进行翻转,请你返回翻转后的链表。
k是一个正整数,它的值小于或等于链表的长度。
如果节点总数不是k的整数倍,那么请将最后剩余的节点保持原有顺序。

示例 :
给定这个链表:1->2->3->4->5
当k= 2 时,应当返回: 2->1->4->3->5
当k= 3 时,应当返回: 3->2->1->4->5

说明 :
你的算法只能使用常数的额外空间。
你不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。

  1. public class ListNode {
  2. int val;
  3. ListNode next;
  4. ListNode(){
  5.  
  6. }
  7. ListNode(int x) { val = x; }
  8. }
  1. /**
  2. * 给定一个链表,两两交换其中相邻的节点,并返回交换后的链表。
  3. * 给你一个链表,每k个节点一组进行翻转,请你返回翻转后的链表。
  4. * k是一个正整数,它的值小于或等于链表的长度。
  5. * 如果节点总数不是k的整数倍,那么请将最后剩余的节点保持原有顺序。
  6. */
  7. public class Subject72 {
  8.  
  9. public ListNode head5 = new ListNode(0);
  10. public ListNode head4 = head5;
  11.  
  12. public static void main(String[] args) {
  13. ListNode listNode0 = new ListNode(1);
  14. ListNode listNode1 = new ListNode(2);
  15. ListNode listNode2 = new ListNode(3);
  16. ListNode listNode3 = new ListNode(-9);
  17. ListNode listNode4 = new ListNode(3);
  18. listNode0.next = listNode1;
  19. listNode1.next = listNode2;
  20. listNode2.next = listNode3;
  21. listNode3.next = listNode4;
  22. ListNode listNode5 = new Subject72().reverseKGroup(listNode0,2);
  23. StringBuilder stringBuilder = null;
  24. while(listNode5 !=null){ //指向位置是否为空
  25. if(stringBuilder == null){
  26. stringBuilder = new StringBuilder();
  27. stringBuilder.append(listNode5.val);
  28. }else{
  29. stringBuilder.append(" -> "+ listNode5.val);
  30. }
  31. listNode5 = listNode5.next; // 指向下一个节点
  32. }
  33. System.out.println(stringBuilder.toString());
  34. }
  35.  
  36. /**
  37. * 逆序K链表
  38. * @param head
  39. * @param k
  40. * @return
  41. */
  42. public ListNode reverseKGroup(ListNode head, int k){
  43. ListNode head0 = head;
  44. ListNode head1 = head;
  45. ListNode head2 = null;
  46. for (int i = 0; i < k-1; i++) {
  47. if(head0 != null){
  48. head0 = head0.next;
  49. }else{
  50. break;
  51. }
  52. }
  53. if(head0 != null){
  54. head2 = head0.next;
  55. head0.next = null;
  56. }else{
  57. head5.next = head;
  58. return head4.next;
  59. }
  60. ListNode head3 = reverseGroup(head);
  61. head5.next = head3;
  62. head5 = head3;
  63. while(head5.next != null){
  64. head5 = head5.next;
  65. }
  66. reverseKGroup(head2,k);
  67. return head4.next;
  68. }
  69.  
  70. /**
  71. * 链表反转
  72. * @param head0
  73. * @return
  74. */
  75. public static ListNode reverseGroup(ListNode head0) {
  76. if(head0==null||head0.next==null){
  77. return head0;
  78. }
  79. ListNode nowHead = reverseGroup(head0.next);
  80. head0.next.next=head0;
  81. head0.next=null;
  82. return nowHead;
  83. }
  84. }

时间复杂度:O(n)

运行结果:

【程序73】
给定一个排序数组,你需要在原地删除重复出现的元素,使得每个元素只出现一次,返回移除后数组的新长度。
不要使用额外的数组空间,你必须在原地修改输入数组并在使用 O(1) 额外空间的条件下完成。

  1. /**
  2. * 给定一个排序数组,你需要在原地删除重复出现的元素,使得每个元素只出现一次,返回移除后数组的新长度。
  3. * 不要使用额外的数组空间,你必须在原地修改输入数组并在使用 O(1) 额外空间的条件下完成。
  4. */
  5. public class Subject73 {
  6. public static void main(String[] args) {
  7. int[] nums = new int[]{1,2,3,4,5,5,6,6,7};
  8. System.out.println(new Subject73().removeDuplicates(nums));
  9. }
  10.  
  11. /**
  12. * 删除重复元素
  13. * @param nums
  14. * @return
  15. */
  16. public int removeDuplicates(int[] nums) {
  17. int lengths = nums.length;
  18. if(lengths <=0 ){
  19. return 0;
  20. }
  21. int side = 0; //空位置
  22. int tmp = nums[0];
  23. boolean flag = true;
  24. for (int i = 1; i < lengths; i++) {
  25. if(tmp == nums[i]){
  26. if(flag){
  27. side = i;
  28. flag = false;
  29. }
  30. }else{
  31. tmp = nums[i];
  32. if(side > 0){
  33. nums[side] = nums[i];
  34. side++;
  35. }
  36. }
  37. }
  38. if(side == 0){
  39. return lengths;
  40. }
  41. return side;
  42. }
  43. }

时间复杂度:O(n)

运行结果:

【程序74】
给定一个数组 nums和一个值 val,你需要原地移除所有数值等于val的元素,返回移除后数组的新长度。
不要使用额外的数组空间,你必须在原地修改输入数组并在使用 O(1) 额外空间的条件下完成。
元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。

  1. /**
  2. * 给定一个数组 nums和一个值 val,你需要原地移除所有数值等于val的元素,返回移除后数组的新长度。
  3. * 不要使用额外的数组空间,你必须在原地修改输入数组并在使用 O(1) 额外空间的条件下完成。
  4. * 元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。
  5. */
  6. public class Subject74 {
  7. public static void main(String[] args) {
  8. int[] nums = new int[]{3,2,2,3};
  9. System.out.println(new Subject74().removeElement(nums,3));
  10. }
  11.  
  12. /**
  13. * 删除元素
  14. * @param nums
  15. * @param val
  16. * @return
  17. */
  18. public static int removeElement(int[] nums, int val) {
  19. int lengths = nums.length;
  20. if(lengths <=0 ){
  21. return 0;
  22. }
  23. int side = 0;
  24. for (int i = 0; i < lengths; i++) {
  25. if(val != nums[i]){
  26. nums[side] = nums[i];
  27. side++;
  28. }
  29. }
  30. return side;
  31. }
  32. }

时间复杂度:O(n)

运行结果:

【程序75】
实现strStr()函数。
给定一个haystack 字符串和一个 needle 字符串,在 haystack 字符串中找出 needle 字符串出现的第一个位置 (从0开始)。如果不存在,则返回 -1。

  1. /**
  2. * 实现strStr()函数。
  3. * 给定一个haystack 字符串和一个 needle 字符串,在 haystack 字符串中找出 needle 字符串出现的第一个位置 (从0开始)。如果不存在,则返回 -1。
  4. */
  5. public class Subject75 {
  6. public static void main(String[] args) {
  7. String haystack = "ssss";
  8. String needle = "a";
  9. System.out.println(new Subject75().strStr(haystack,needle));
  10. }
  11.  
  12. /**
  13. * 实现strStr()函数
  14. */
  15. public int strStr(String haystack, String needle) {
  16. if("".equals(needle) || needle == null){
  17. return 0;
  18. }else{
  19. if("".equals(haystack) || haystack == null ){
  20. return -1;
  21. }
  22. }
  23. char[] arr0= haystack.toCharArray();
  24. char[] arr1= needle.toCharArray();
  25. return strStr0(arr0,arr1,0,arr0.length,-1);
  26. }
  27.  
  28. /**
  29. * 递归处理
  30. * @param arr0
  31. * @param arr1
  32. * @param side
  33. * @param lengths0
  34. * @param result
  35. * @return
  36. */
  37. public int strStr0(char[] arr0, char[] arr1,int side,int lengths0,int result) {
  38. if(result == 0){
  39. return side-1;
  40. }
  41. boolean flag = false;
  42. for (int i = side; i < lengths0; i++) {
  43. if(arr0[i] == arr1[0]){
  44. side = i;
  45. flag = true;
  46. break;
  47. }
  48. }
  49. int tmp = lengths0 - side;
  50. int lengths1 = arr1.length;
  51. if(tmp < lengths1 || !flag){
  52. return -1;
  53. }else{
  54. int identification = 0;
  55. for (int i = 1, j = side+1; i < lengths1; i++,j++) {
  56. if(arr0[j] != arr1[i]){
  57. identification = -1;
  58. break;
  59. }
  60. }
  61. side = side+1;
  62. return strStr0(arr0,arr1,side, lengths0,identification);
  63. }
  64. }
  65. }

时间复杂度:O(n)

运行结果:

【程序76】
给定两个整数,被除数dividend和除数divisor。将两数相除,要求不使用乘法、除法和 mod 运算符。
返回被除数dividend除以除数divisor得到的商。

  1. /**
  2. * 给定两个整数,被除数dividend和除数divisor。将两数相除,要求不使用乘法、除法和 mod 运算符。
  3. * 返回被除数dividend除以除数divisor得到的商。
  4. */
  5. public class Subject76 {
  6. public static void main(String[] args) {
  7. int dividend = -2147483648;
  8. int divisor = -1;
  9. System.out.println(-2147483648/2);
  10. System.out.println(new Subject76().divide(dividend,divisor));
  11. }
  12.  
  13. /**
  14. * 实现除法,通过竖式的方式
  15. * @param dividend
  16. * @param divisor
  17. * @return
  18. */
  19. public int divide(int dividend, int divisor) {
  20. //排除一些特殊结果
  21. if(dividend == 0){
  22. return 0;
  23. }
  24. if(divisor == Integer.MIN_VALUE){
  25. if(dividend > Integer.MIN_VALUE){
  26. return 0;
  27. }else{
  28. return 1;
  29. }
  30. }
  31.  
  32. if(divisor == 1){
  33. return dividend;
  34. }
  35. if(divisor == -1){
  36. if(dividend == Integer.MIN_VALUE) {
  37. return Integer.MAX_VALUE;
  38. }else{
  39. return -dividend;
  40. }
  41. }
  42. int result = 0;
  43. String s0 = String.valueOf(dividend);
  44. String s1 = String.valueOf(divisor);
  45. boolean flag = false;
  46. if(s0.charAt(0) == '-'){
  47. flag = true;
  48. }else{
  49. s0 = "-"+s0;
  50. }
  51.  
  52. if(s1.charAt(0) == '-'){
  53. if(flag){
  54. flag = false;
  55. }else{
  56. flag = true;
  57. }
  58. }else{
  59. s1 = "-"+s1;
  60. divisor = -divisor;
  61. }
  62. int side = s1.length()-1;
  63. if(side > s0.length()-1){
  64. return 0;
  65. }
  66. int dividend0 = Integer.parseInt(s0.substring(0,side+1)); //临时除数
  67. while(true){
  68. side++;
  69. int num = dividend0 - divisor;
  70. int i = 0;
  71. while(num <= 0){
  72. i++;
  73. num = num - divisor;
  74. }
  75. result = Integer.parseInt(result+"0") + i;
  76. if(side >= s0.length()){
  77. break;
  78. }else{
  79. dividend0 = Integer.parseInt((num+divisor)+ "" +s0.charAt(side));
  80. if(dividend0 > 0){
  81. dividend0 = -dividend0;
  82. }
  83. }
  84. }
  85.  
  86. if(flag){
  87. return -result;
  88. }else{
  89. return result;
  90. }
  91. }
  92. }

时间复杂度:O(1)

运行结果:

【程序77】
给定一个字符串s和一些长度相同的单词words。找出 s 中恰好可以由words 中所有单词串联形成的子串的起始位置。
注意子串要与words 中的单词完全匹配,中间不能有其他字符,但不需要考虑words中单词串联的顺序。

  1. import java.util.ArrayList;
  2. import java.util.HashMap;
  3. import java.util.List;
  4.  
  5. /**
  6. * 给定一个字符串s和一些长度相同的单词words。找出 s 中恰好可以由words 中所有单词串联形成的子串的起始位置。
  7. * 注意子串要与words 中的单词完全匹配,中间不能有其他字符,但不需要考虑words中单词串联的顺序。
  8. */
  9. public class Subject77 {
  10. public static void main(String[] args) {
  11. String s = "ababaabababababababababababababababababababababababbababababab";
  12. String[] words = new String[]{"ab","ba","ab","ba","ab","ba","ab","ba","ab","ba","ab","ba","ab","ba","ab","ba","ab","ba"};
  13. System.out.println(words.length);
  14. List<Integer> list = new Subject77().findSubstring(s,words);
  15. System.out.println(list);
  16. }
  17.  
  18. public List<Integer> findSubstring(String s, String[] words) {
  19. List<Integer> res = new ArrayList<Integer>();
  20. int wordNum = words.length;
  21. if (wordNum == 0) {
  22. return res;
  23. }
  24. int wordLen = words[0].length();
  25. HashMap<String, Integer> allWords = new HashMap<String, Integer>();
  26. for (String w : words) {
  27. int value = allWords.getOrDefault(w, 0);
  28. allWords.put(w, value + 1);
  29. }
  30. //将所有移动分成 wordLen 类情况
  31. for (int j = 0; j < wordLen; j++) {
  32. HashMap<String, Integer> hasWords = new HashMap<String, Integer>();
  33. int num = 0; //记录当前 HashMap2(这里的 hasWords 变量)中有多少个单词
  34. //每次移动一个单词长度
  35. for (int i = j; i < s.length() - wordNum * wordLen + 1; i = i + wordLen) {
  36. boolean hasRemoved = false; //防止情况三移除后,情况一继续移除
  37. while (num < wordNum) {
  38. String word = s.substring(i + num * wordLen, i + (num + 1) * wordLen);
  39. if (allWords.containsKey(word)) {
  40. int value = hasWords.getOrDefault(word, 0);
  41. hasWords.put(word, value + 1);
  42. //出现情况三,遇到了符合的单词,但是次数超了
  43. if (hasWords.get(word) > allWords.get(word)) {
  44. // hasWords.put(word, value);
  45. hasRemoved = true;
  46. int removeNum = 0;
  47. //一直移除单词,直到次数符合了
  48. while (hasWords.get(word) > allWords.get(word)) {
  49. String firstWord = s.substring(i + removeNum * wordLen, i + (removeNum + 1) * wordLen);
  50. int v = hasWords.get(firstWord);
  51. hasWords.put(firstWord, v - 1);
  52. removeNum++;
  53. }
  54. num = num - removeNum + 1; //加 1 是因为我们把当前单词加入到了 HashMap 2 中
  55. i = i + (removeNum - 1) * wordLen; //这里依旧是考虑到了最外层的 for 循环,看情况二的解释
  56. break;
  57. }
  58. //出现情况二,遇到了不匹配的单词,直接将 i 移动到该单词的后边(但其实这里
  59. //只是移动到了出现问题单词的地方,因为最外层有 for 循环, i 还会移动一个单词
  60. //然后刚好就移动到了单词后边)
  61. } else {
  62. hasWords.clear();
  63. i = i + num * wordLen;
  64. num = 0;
  65. break;
  66. }
  67. num++;
  68. }
  69. if (num == wordNum) {
  70. res.add(i);
  71.  
  72. }
  73. //出现情况一,子串完全匹配,我们将上一个子串的第一个单词从 HashMap2 中移除
  74. if (num > 0 && !hasRemoved) {
  75. String firstWord = s.substring(i, i + wordLen);
  76. int v = hasWords.get(firstWord);
  77. hasWords.put(firstWord, v - 1);
  78. num = num - 1;
  79. }
  80. }
  81. }
  82. return res;
  83. }
  84. }

时间复杂度:O(n)

运行结果:

以上题目均来自:https://leetcode-cn.com/ ,如果你热爱编码,热爱算法,该网站一定适合你。

《Java练习题》进阶练习题(三)的更多相关文章

  1. java语言进阶(三)_List_Set_数据结构_Collections

    主要内容 数据结构 List集合 Set集合 Collections 第一章 数据结构 1.1 数据结构有什么用? 常见的数据结构:堆.栈.队列.数组.链表和红黑树 . 1.2 常见的数据结构 栈 栈 ...

  2. 【视频+图文】Java经典基础练习题(三):输入3个整数,并将其由小到大输出

    目录 一.视频讲解 二.思路分析 总结: 三.代码+详解+结果 四.彩蛋 能解决题目的代码并不是一次就可以写好的 我们需要根据我们的思路写出后通过debug模式找到不足再进行更改 多次测试后才可得到能 ...

  3. 6、50道JAVA基础编程练习题跟答案

    50道JAVA基础编程练习题 [程序1] 题目:古典问题:有一对兔子,从出生后第3个月起每个月都生一对兔子,小兔子长到第三个月后每个月又生一对兔子,假如兔子都不死,问每个月的兔子总数为多少? 程序分析 ...

  4. 50道JAVA基础编程练习题

    50道JAVA基础编程练习题 [程序1] 题目:古典问题:有一对兔子,从出生后第3个月起每个月都生一对兔子,小兔子长到第三个月后每个月又生一对兔子,假如兔子都不死,问每个月的兔子对数为多少? 程序分析 ...

  5. 50道JAVA基础编程练习题 - 题目

    50道JAVA基础编程练习题[1]题目:古典问题:有一对兔子,从出生后第3个月起每个月都生一对兔子,小兔子长到第三个月后每个月又生一对兔子,假如兔子都不死,问每个月的兔子总数为多少? [2]题目:判断 ...

  6. Java进阶(三)多线程开发关键技术

    原创文章,同步发自作者个人博客,转载请务必以超链接形式在文章开头处注明出处http://www.jasongj.com/java/multi_thread/. sleep和wait到底什么区别 其实这 ...

  7. 【视频+图文】Java基础经典练习题(一)输出2-100之间的素数,及素数个数

    目录 第一题:判断2-100之间有多少个素数,并输出所有素数. 1.视频讲解: 2.思路分析: 代码讲解:以i=4为例 4.为大家准备了彩蛋: 能解决题目的代码并不是一次就可以写好的 我们需要根据我们 ...

  8. # 2019-2020-3 《Java 程序设计》第三周总结

    2019-2020-3 <Java 程序设计>第三周知识总结 1.类的定义 语法格式如下(加[]表示可选项): [修饰符] class 类名 { 属性定义(声明) 方法定义(声明)} 2. ...

  9. Java字符串进阶

    Java字符串进阶 前言 最常用的对字符串操作的类有三个,分别是String,StringBuilder,StringBuffer,下面将会详细的说说这三个类...... String String类 ...

  10. Java 入门进阶

    Java 入门进阶 發表於 2015-04-16 http://xielong.me/2015/04/16/%E6%9C%8D%E5%8A%A1%E7%AB%AF%E5%B7%A5%E7%A8%8B% ...

随机推荐

  1. js数组合并以及对象的遍历

    这是很基础的知识,but,对于一只未系统学习过js,只略懂搬砖的跨界狗,还是经常犯错: 场景:移动端上拉加载更多. 初始数组合并后来请求的数组. 使用concat方法,不过要主要: 使用concat, ...

  2. 根据本地ip获取地理位置,再根据地理位置,获取天气

    import json,requestsfrom urllib.request import urlopenfrom pyquery import PyQuery as pqfrom lxml imp ...

  3. 初探SpringMVC,走进SpringMVC的世界

    1.Springmvc入门 1.1.Springmvc是什么 SpringMVC是Spring中的一个组件,目前(2019)在互联网公司用的很多,是必需学习的一门框架技术!SpringMVC用于web ...

  4. SQL基础语句(详解版)

    版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明.本文链接:https://blog.csdn.net/CZXY18ji/article/deta ...

  5. JS使用readAsDataURL读取图像文件

    JS使用readAsDataURL读取图像文件 FileReader对象的readAsDataURL方法可以将读取到的文件编码成Data URL.Data URL是一项特殊的技术,可以将资料(例如图片 ...

  6. react可拖动的好用的树结构插件

    react tree 可拖动树结构: github地址: github地址:react-sortable-tree 安装: NPM npm install react-sortable-tree –s ...

  7. jsp实现增加数据功能

    1. 环境的搭建 软件 数据库  sql myeclipse 8.0  tomcat 6.0 2. 安装完 myeclipse 配置下  部署tomcat 6.0 =1=> =2=>  新 ...

  8. C# 子类与父类构造函数

  9. react-native技术调研:react-native是什么?

    如有疏漏错误,还望指正.转载不忘加上>>原链接<<哦~ react-native是什么? react-native原理 从字面意思上来看,react-native由单词reac ...

  10. 关于Python的随机数模块,你必须要掌握!

    所谓七夕 前几天的文章这个七夕节,用Python为女友绘制一张爱心照片墙吧!收获了最近以来最高的浏览量,没枉费我熬到夜里3点赶出来的热点文章.有付出就总会有所回报,只是看这天来的早晚而已.七夕一个人看 ...