編程合集: https://www.cnblogs.com/jssj/p/12002760.html
前言:不僅僅要實現,更要提升性能,精益求精,用盡量少的時間復雜度和空間復雜度解決問題。
【程序68】
將兩個有序鏈表合並為一個新的有序鏈表並返回。新鏈表是通過拼接給定的兩個鏈表的所有節點組成的。
public class ListNode { int val; ListNode next; ListNode(){ } ListNode(int x) { val = x; } }
/** * 將兩個有序鏈表合並為一個新的有序鏈表並返回。新鏈表是通過拼接給定的兩個鏈表的所有節點組成的。 */ public class Subject68 { public static void main(String[] args) { ListNode listNode0 = new ListNode(1); ListNode listNode1 = new ListNode(2); ListNode listNode2 = new ListNode(3); ListNode listNode3 = new ListNode(-9); ListNode listNode4 = new ListNode(3); listNode0.next = listNode1; listNode1.next = listNode2; listNode2.next = listNode3; listNode3.next = listNode4; ListNode listNode01 = new ListNode(5); ListNode listNode11 = new ListNode(7); listNode01.next = listNode11; ListNode tmp = mergeTwoLists(listNode3,listNode01); StringBuilder stringBuilder = null; while(tmp !=null){ //指向位置是否為空 if(stringBuilder == null){ stringBuilder = new StringBuilder(); stringBuilder.append(tmp.val); }else{ stringBuilder.append(" -> "+ tmp.val); } tmp = tmp.next; // 指向下一個節點 } System.out.println(stringBuilder.toString()); } /** * 遞歸實現鏈表插入 * @param l1 * @param l2 * @return */ public static ListNode mergeTwoLists(ListNode l1, ListNode l2) { if (l1 == null) { return l2; } else if (l2 == null) { return l1; } else if (l1.val < l2.val) { l1.next = mergeTwoLists(l1.next, l2); return l1; } else { l2.next = mergeTwoLists(l1, l2.next); return l2; } } }
時間復雜度:O(n+m)
運行結果:

【程序69】
給出 n 代表生成括號的對數,請你寫出一個函數,使其能夠生成所有可能的並且有效的括號組合。
import java.util.ArrayList; import java.util.List; /** * 給出 n 代表生成括號的對數,請你寫出一個函數,使其能夠生成所有可能的並且有效的括號組合。 */ public class Subject69 { public static void main(String[] args) { System.out.println(generateParenthesis(4)); } /** * 遞歸解題 * @param n * @return */ public static List<String> generateParenthesis(int n) { if(n == 1){ List<String> list = new ArrayList<>(); list.add("()"); return list; }else{ List<String> list = generateParenthesis(n-1); int sizes = list.size(); List<String> newList = new ArrayList<>(); for (int i = 0; i < sizes; i++) { String tmp = list.get(i); char[] arr = tmp.toCharArray(); for (int j = 0; j < arr.length; j++) { String tmp0 = tmp.substring(0,j); String tmp1 = tmp.substring(j,tmp.length()); String tmp2 = tmp0 + "()" +tmp1; if(!newList.contains(tmp2)){ newList.add(tmp2); } } } return newList; } } }

運行結果:

【程序70】
合並 k 個排序鏈表,返回合並后的排序鏈表。請分析和描述算法的復雜度。
public class ListNode { int val; ListNode next; ListNode(){ } ListNode(int x) { val = x; } }
/** * 合並 k 個排序鏈表,返回合並后的排序鏈表。請分析和描述算法的復雜度。 */ public class Subject70 { public static void main(String[] args) { ListNode listNode0 = new ListNode(-10); ListNode listNode1 = new ListNode(-9); ListNode listNode2 = new ListNode(-9); ListNode listNode3 = new ListNode(-3); ListNode listNode4 = new ListNode(-1); ListNode listNode5 = new ListNode(-1); ListNode listNode6 = new ListNode(0); listNode1.next = listNode0; listNode2.next = listNode1; listNode3.next = listNode2; listNode4.next = listNode3; listNode5.next = listNode4; listNode6.next = listNode5; ListNode listNode01 = new ListNode(-5); ListNode listNode02 = new ListNode(4); ListNode listNode03 = new ListNode(-8); ListNode listNode11 = null; ListNode listNode20 = new ListNode(-9); ListNode listNode21 = new ListNode(-6); ListNode listNode22 = new ListNode(-5); ListNode listNode23 = new ListNode(-4); ListNode listNode24 = new ListNode(-2); ListNode listNode25 = new ListNode(2); ListNode listNode26 = new ListNode(3); listNode21.next = listNode20; listNode22.next = listNode21; listNode23.next = listNode22; listNode24.next = listNode23; listNode25.next = listNode24; listNode26.next = listNode25; ListNode listNode30 = new ListNode(-3); ListNode listNode31 = new ListNode(-3); ListNode listNode32 = new ListNode(-2); ListNode listNode33 = new ListNode(-1); ListNode listNode34 = new ListNode(0); listNode31.next = listNode30; listNode32.next = listNode31; listNode33.next = listNode32; listNode34.next = listNode33; ListNode[] arr = new ListNode[]{listNode6,listNode01,listNode02,listNode03,listNode11,listNode26,listNode34}; ListNode tmp= mergeKLists(arr); StringBuilder stringBuilder = null; while(tmp !=null){ //指向位置是否為空 if(stringBuilder == null){ stringBuilder = new StringBuilder(); stringBuilder.append(tmp.val); }else{ stringBuilder.append(" -> "+ tmp.val); } tmp = tmp.next; // 指向下一個節點 } System.out.println(stringBuilder.toString()); } /** * 合並鏈表 * @param lists * @return */ public static ListNode mergeKLists(ListNode[] lists) { if(lists.length == 0){ return null; } ListNode[] arr = mergeKLists0(lists); return arr[0]; } /** * 使用合並算法,組合鏈表 * @param lists * @return */ public static ListNode[] mergeKLists0(ListNode[] lists) { int length = lists.length; if(length == 1){ return lists; } ListNode[] listTmp = new ListNode[(int)Math.ceil(length/2.0)]; ListNode[] listTmp0 = null; for (int i = 0 ,j = 0; i < length; i = i+2 , j++) { ListNode tmp0 = null; if(i+1 <= length-1){ tmp0 = mergeTwoLists(lists[i],lists[i+1]); }else{ tmp0 = mergeTwoLists(lists[i],null); } listTmp[j] = tmp0; } listTmp0 = mergeKLists0(listTmp); return listTmp0; } /** * 遞歸實現鏈表插入 * @param l1 * @param l2 * @return */ public static ListNode mergeTwoLists(ListNode l1, ListNode l2) { if (l1 == null) { return l2; } else if (l2 == null) { return l1; } else if (l1.val < l2.val) { l1.next = mergeTwoLists(l1.next, l2); return l1; } else { l2.next = mergeTwoLists(l1, l2.next); return l2; } } }
時間復雜度:O(Nlogk)
運行結果:

【程序71】
給定一個鏈表,兩兩交換其中相鄰的節點,並返回交換后的鏈表。
public class ListNode { int val; ListNode next; ListNode(){ } ListNode(int x) { val = x; } }
/** * 給定一個鏈表,兩兩交換其中相鄰的節點,並返回交換后的鏈表。 */ public class Subject71 { public static void main(String[] args) { ListNode listNode0 = new ListNode(1); ListNode listNode1 = new ListNode(2); ListNode listNode2 = new ListNode(3); ListNode listNode3 = new ListNode(-9); ListNode listNode4 = new ListNode(3); listNode0.next = listNode1; listNode1.next = listNode2; listNode2.next = listNode3; listNode3.next = listNode4; ListNode tmp = swapPairs(listNode0); StringBuilder stringBuilder = null; while(tmp !=null){ //指向位置是否為空 if(stringBuilder == null){ stringBuilder = new StringBuilder(); stringBuilder.append(tmp.val); }else{ stringBuilder.append(" -> "+ tmp.val); } tmp = tmp.next; // 指向下一個節點 } System.out.println(stringBuilder.toString()); } /** * 交換鏈表數據位置 * @param head * @return */ public static ListNode swapPairs(ListNode head) { ListNode newHead = new ListNode(0); ListNode resultHead = newHead; while(head != null){ ListNode tmp0 = new ListNode(head.val); ListNode tmp1 = null; if(head.next != null){ tmp1 = new ListNode(head.next.val); newHead.next = tmp1; tmp1.next = tmp0; head = head.next.next; }else{ newHead.next = tmp0; head = null; } newHead = tmp0; } return resultHead.next; } }
時間復雜度: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
說明 :
你的算法只能使用常數的額外空間。
你不能只是單純的改變節點內部的值,而是需要實際的進行節點交換。
public class ListNode { int val; ListNode next; ListNode(){ } ListNode(int x) { val = x; } }
/** * 給定一個鏈表,兩兩交換其中相鄰的節點,並返回交換后的鏈表。 * 給你一個鏈表,每k個節點一組進行翻轉,請你返回翻轉后的鏈表。 * k是一個正整數,它的值小於或等於鏈表的長度。 * 如果節點總數不是k的整數倍,那么請將最后剩余的節點保持原有順序。 */ public class Subject72 { public ListNode head5 = new ListNode(0); public ListNode head4 = head5; public static void main(String[] args) { ListNode listNode0 = new ListNode(1); ListNode listNode1 = new ListNode(2); ListNode listNode2 = new ListNode(3); ListNode listNode3 = new ListNode(-9); ListNode listNode4 = new ListNode(3); listNode0.next = listNode1; listNode1.next = listNode2; listNode2.next = listNode3; listNode3.next = listNode4; ListNode listNode5 = new Subject72().reverseKGroup(listNode0,2); StringBuilder stringBuilder = null; while(listNode5 !=null){ //指向位置是否為空 if(stringBuilder == null){ stringBuilder = new StringBuilder(); stringBuilder.append(listNode5.val); }else{ stringBuilder.append(" -> "+ listNode5.val); } listNode5 = listNode5.next; // 指向下一個節點 } System.out.println(stringBuilder.toString()); } /** * 逆序K鏈表 * @param head * @param k * @return */ public ListNode reverseKGroup(ListNode head, int k){ ListNode head0 = head; ListNode head1 = head; ListNode head2 = null; for (int i = 0; i < k-1; i++) { if(head0 != null){ head0 = head0.next; }else{ break; } } if(head0 != null){ head2 = head0.next; head0.next = null; }else{ head5.next = head; return head4.next; } ListNode head3 = reverseGroup(head); head5.next = head3; head5 = head3; while(head5.next != null){ head5 = head5.next; } reverseKGroup(head2,k); return head4.next; } /** * 鏈表反轉 * @param head0 * @return */ public static ListNode reverseGroup(ListNode head0) { if(head0==null||head0.next==null){ return head0; } ListNode nowHead = reverseGroup(head0.next); head0.next.next=head0; head0.next=null; return nowHead; } }
時間復雜度:O(n)
運行結果:

【程序73】
給定一個排序數組,你需要在原地刪除重復出現的元素,使得每個元素只出現一次,返回移除后數組的新長度。
不要使用額外的數組空間,你必須在原地修改輸入數組並在使用 O(1) 額外空間的條件下完成。
/** * 給定一個排序數組,你需要在原地刪除重復出現的元素,使得每個元素只出現一次,返回移除后數組的新長度。 * 不要使用額外的數組空間,你必須在原地修改輸入數組並在使用 O(1) 額外空間的條件下完成。 */ public class Subject73 { public static void main(String[] args) { int[] nums = new int[]{1,2,3,4,5,5,6,6,7}; System.out.println(new Subject73().removeDuplicates(nums)); } /** * 刪除重復元素 * @param nums * @return */ public int removeDuplicates(int[] nums) { int lengths = nums.length; if(lengths <=0 ){ return 0; } int side = 0; //空位置 int tmp = nums[0]; boolean flag = true; for (int i = 1; i < lengths; i++) { if(tmp == nums[i]){ if(flag){ side = i; flag = false; } }else{ tmp = nums[i]; if(side > 0){ nums[side] = nums[i]; side++; } } } if(side == 0){ return lengths; } return side; } }
時間復雜度:O(n)
運行結果:

【程序74】
給定一個數組 nums和一個值 val,你需要原地移除所有數值等於val的元素,返回移除后數組的新長度。
不要使用額外的數組空間,你必須在原地修改輸入數組並在使用 O(1) 額外空間的條件下完成。
元素的順序可以改變。你不需要考慮數組中超出新長度后面的元素。
/** * 給定一個數組 nums和一個值 val,你需要原地移除所有數值等於val的元素,返回移除后數組的新長度。 * 不要使用額外的數組空間,你必須在原地修改輸入數組並在使用 O(1) 額外空間的條件下完成。 * 元素的順序可以改變。你不需要考慮數組中超出新長度后面的元素。 */ public class Subject74 { public static void main(String[] args) { int[] nums = new int[]{3,2,2,3}; System.out.println(new Subject74().removeElement(nums,3)); } /** * 刪除元素 * @param nums * @param val * @return */ public static int removeElement(int[] nums, int val) { int lengths = nums.length; if(lengths <=0 ){ return 0; } int side = 0; for (int i = 0; i < lengths; i++) { if(val != nums[i]){ nums[side] = nums[i]; side++; } } return side; } }
時間復雜度:O(n)
運行結果:

【程序75】
實現strStr()函數。
給定一個haystack 字符串和一個 needle 字符串,在 haystack 字符串中找出 needle 字符串出現的第一個位置 (從0開始)。如果不存在,則返回 -1。
/** * 實現strStr()函數。 * 給定一個haystack 字符串和一個 needle 字符串,在 haystack 字符串中找出 needle 字符串出現的第一個位置 (從0開始)。如果不存在,則返回 -1。 */ public class Subject75 { public static void main(String[] args) { String haystack = "ssss"; String needle = "a"; System.out.println(new Subject75().strStr(haystack,needle)); } /** * 實現strStr()函數 */ public int strStr(String haystack, String needle) { if("".equals(needle) || needle == null){ return 0; }else{ if("".equals(haystack) || haystack == null ){ return -1; } } char[] arr0= haystack.toCharArray(); char[] arr1= needle.toCharArray(); return strStr0(arr0,arr1,0,arr0.length,-1); } /** * 遞歸處理 * @param arr0 * @param arr1 * @param side * @param lengths0 * @param result * @return */ public int strStr0(char[] arr0, char[] arr1,int side,int lengths0,int result) { if(result == 0){ return side-1; } boolean flag = false; for (int i = side; i < lengths0; i++) { if(arr0[i] == arr1[0]){ side = i; flag = true; break; } } int tmp = lengths0 - side; int lengths1 = arr1.length; if(tmp < lengths1 || !flag){ return -1; }else{ int identification = 0; for (int i = 1, j = side+1; i < lengths1; i++,j++) { if(arr0[j] != arr1[i]){ identification = -1; break; } } side = side+1; return strStr0(arr0,arr1,side, lengths0,identification); } } }
時間復雜度:O(n)
運行結果:

【程序76】
給定兩個整數,被除數dividend和除數divisor。將兩數相除,要求不使用乘法、除法和 mod 運算符。
返回被除數dividend除以除數divisor得到的商。
/** * 給定兩個整數,被除數dividend和除數divisor。將兩數相除,要求不使用乘法、除法和 mod 運算符。 * 返回被除數dividend除以除數divisor得到的商。 */ public class Subject76 { public static void main(String[] args) { int dividend = -2147483648; int divisor = -1; System.out.println(-2147483648/2); System.out.println(new Subject76().divide(dividend,divisor)); } /** * 實現除法,通過豎式的方式 * @param dividend * @param divisor * @return */ public int divide(int dividend, int divisor) { //排除一些特殊結果 if(dividend == 0){ return 0; } if(divisor == Integer.MIN_VALUE){ if(dividend > Integer.MIN_VALUE){ return 0; }else{ return 1; } } if(divisor == 1){ return dividend; } if(divisor == -1){ if(dividend == Integer.MIN_VALUE) { return Integer.MAX_VALUE; }else{ return -dividend; } } int result = 0; String s0 = String.valueOf(dividend); String s1 = String.valueOf(divisor); boolean flag = false; if(s0.charAt(0) == '-'){ flag = true; }else{ s0 = "-"+s0; } if(s1.charAt(0) == '-'){ if(flag){ flag = false; }else{ flag = true; } }else{ s1 = "-"+s1; divisor = -divisor; } int side = s1.length()-1; if(side > s0.length()-1){ return 0; } int dividend0 = Integer.parseInt(s0.substring(0,side+1)); //臨時除數 while(true){ side++; int num = dividend0 - divisor; int i = 0; while(num <= 0){ i++; num = num - divisor; } result = Integer.parseInt(result+"0") + i; if(side >= s0.length()){ break; }else{ dividend0 = Integer.parseInt((num+divisor)+ "" +s0.charAt(side)); if(dividend0 > 0){ dividend0 = -dividend0; } } } if(flag){ return -result; }else{ return result; } } }
時間復雜度:O(1)
運行結果:

【程序77】
給定一個字符串s和一些長度相同的單詞words。找出 s 中恰好可以由words 中所有單詞串聯形成的子串的起始位置。
注意子串要與words 中的單詞完全匹配,中間不能有其他字符,但不需要考慮words中單詞串聯的順序。
import java.util.ArrayList; import java.util.HashMap; import java.util.List; /** * 給定一個字符串s和一些長度相同的單詞words。找出 s 中恰好可以由words 中所有單詞串聯形成的子串的起始位置。 * 注意子串要與words 中的單詞完全匹配,中間不能有其他字符,但不需要考慮words中單詞串聯的順序。 */ public class Subject77 { public static void main(String[] args) { String s = "ababaabababababababababababababababababababababababbababababab"; String[] words = new String[]{"ab","ba","ab","ba","ab","ba","ab","ba","ab","ba","ab","ba","ab","ba","ab","ba","ab","ba"}; System.out.println(words.length); List<Integer> list = new Subject77().findSubstring(s,words); System.out.println(list); } public List<Integer> findSubstring(String s, String[] words) { List<Integer> res = new ArrayList<Integer>(); int wordNum = words.length; if (wordNum == 0) { return res; } int wordLen = words[0].length(); HashMap<String, Integer> allWords = new HashMap<String, Integer>(); for (String w : words) { int value = allWords.getOrDefault(w, 0); allWords.put(w, value + 1); } //將所有移動分成 wordLen 類情況 for (int j = 0; j < wordLen; j++) { HashMap<String, Integer> hasWords = new HashMap<String, Integer>(); int num = 0; //記錄當前 HashMap2(這里的 hasWords 變量)中有多少個單詞 //每次移動一個單詞長度 for (int i = j; i < s.length() - wordNum * wordLen + 1; i = i + wordLen) { boolean hasRemoved = false; //防止情況三移除后,情況一繼續移除 while (num < wordNum) { String word = s.substring(i + num * wordLen, i + (num + 1) * wordLen); if (allWords.containsKey(word)) { int value = hasWords.getOrDefault(word, 0); hasWords.put(word, value + 1); //出現情況三,遇到了符合的單詞,但是次數超了 if (hasWords.get(word) > allWords.get(word)) { // hasWords.put(word, value); hasRemoved = true; int removeNum = 0; //一直移除單詞,直到次數符合了 while (hasWords.get(word) > allWords.get(word)) { String firstWord = s.substring(i + removeNum * wordLen, i + (removeNum + 1) * wordLen); int v = hasWords.get(firstWord); hasWords.put(firstWord, v - 1); removeNum++; } num = num - removeNum + 1; //加 1 是因為我們把當前單詞加入到了 HashMap 2 中 i = i + (removeNum - 1) * wordLen; //這里依舊是考慮到了最外層的 for 循環,看情況二的解釋 break; } //出現情況二,遇到了不匹配的單詞,直接將 i 移動到該單詞的后邊(但其實這里 //只是移動到了出現問題單詞的地方,因為最外層有 for 循環, i 還會移動一個單詞 //然后剛好就移動到了單詞后邊) } else { hasWords.clear(); i = i + num * wordLen; num = 0; break; } num++; } if (num == wordNum) { res.add(i); } //出現情況一,子串完全匹配,我們將上一個子串的第一個單詞從 HashMap2 中移除 if (num > 0 && !hasRemoved) { String firstWord = s.substring(i, i + wordLen); int v = hasWords.get(firstWord); hasWords.put(firstWord, v - 1); num = num - 1; } } } return res; } }
時間復雜度:O(n)
運行結果:

以上題目均來自:https://leetcode-cn.com/ ,如果你熱愛編碼,熱愛算法,該網站一定適合你。
