這個是LeetCode上面的編程訓練專項頁面,地址:https://leetcode-cn.com/explore/interview/card/top-interview-quesitons-in-2018/262/summery/java
整體,比較系統、全面。在解決這些問題的時候,我都是先嚐試使用本身的方法coding一遍,以後在看看其餘比較巧妙的解決方法學習一下。面試
須要特殊技巧解決的難題:①切割回文;②正則表達式
給定一個非空整數數組,除了某個元素只出現一次之外,其他每一個元素均出現兩次。找出那個只出現了一次的元素。算法
package com.cnblogs.mufasa.QA1_makeAhotDOU; import org.junit.Test; import java.util.Arrays; public class Solution1 { //速度也還行,時間複雜度大體爲O(nlogn+n/2),相對性能要差一些 public static int singleNumber1(int[] nums) { Arrays.sort(nums); int len=nums.length-1; for(int i=0;i<len;i+=2){ if(nums[i]!=nums[i+1]){ return nums[i]; } } return nums[len]; } //***最優化的解法***,時間複雜度爲O(n) public static int singleNumber(int[] nums) { int temp=nums[0]; for(int i=1;i<nums.length;i++){ temp^=nums[i]; } return temp; } @Test public void test() { // int[] nums=new int[]{1,1,2,2,6,7,7,6}; int[] nums=new int[]{4,1,2,1,2}; System.out.println(singleNumber(nums)); System.out.println(singleNumber1(nums)); } }
給定一個大小爲 n 的數組,找到其中的衆數。衆數是指在數組中出現次數大於 ⌊ n/2 ⌋
的元素。編程
你能夠假設數組是非空的,而且給定的數組老是存在衆數。數組
package com.cnblogs.mufasa.QA1_makeAhotDOU; import org.junit.Test; import java.util.Arrays; import java.util.Map; import java.util.TreeMap; public class Solution2 { //最完美的解決方法,時間複雜度能夠下降到O(NlogN) public int majorityElement1(int[] nums) { Arrays.sort(nums); return nums[nums.length/2]; } //利用TreeMap來進行排序,更新出現頻率大小 public int majorityElement(int[] nums) { TreeMap<Integer,Integer> treeMap=new TreeMap<>(); for(int i=0;i<nums.length;i++){ if(treeMap.get(nums[i])!=null){ treeMap.put(nums[i],treeMap.get(nums[i])+1); }else { treeMap.put(nums[i],1); } } int loc=-1,max=0; for(Map.Entry<Integer,Integer> kv:treeMap.entrySet()){ if(kv.getValue()>max){ loc=kv.getKey(); max=kv.getValue(); if(max>nums.length/2){ break; } } } return loc; } @Test public void test() { int[] nums=new int[]{2,2,1,1,1,2,2}; System.out.println(majorityElement1(nums)); System.out.println(majorityElement(nums)); } }
編寫一個高效的算法來搜索 m x n 矩陣 matrix 中的一個目標值 target。該矩陣具備如下特性:性能優化
package com.cnblogs.mufasa.QA1_makeAhotDOU; import org.junit.Test; public class Solution3 { //1,暴力破解法【遍歷全部位置】因爲題目已經給出這個matrix是有序的,因此暴力法明顯就浪費了這種已知條件 public boolean searchMatrix1(int[][] matrix, int target) { if(matrix==null||matrix.length==0||matrix[0].length==0){ return false; } int xLen=matrix.length,yLen=matrix[0].length; for(int i=0;i<xLen;i++){ for(int j=0;j<yLen;j++){ if(matrix[i][j]==target){ return true; } } } return false; } //2,二分查找法,利用上有序這一條件 public boolean searchMatrix(int[][] matrix, int target) { if(matrix==null||matrix.length==0||matrix[0].length==0){ return false; } int x=matrix.length-1; int y=0,yLen=matrix[0].length; while (y<yLen&&x>=0){ if(matrix[x][y]>target){ x--; }else if(matrix[x][y]<target){ y++; }else { return true; } } return false; } @Test public void test(){ int[][] matrix={ {1, 4, 7, 11, 15}, {2, 5, 8, 12, 19}, {3, 6, 9, 16, 22}, {10, 13, 14, 17, 24}, {18, 21, 23, 26, 30}}; // System.out.println(searchMatrix(matrix,5)); // System.out.println(searchMatrix(matrix,20)); System.out.println(searchMatrix(matrix,22)); } }
給定兩個有序整數數組 nums1 和 nums2,將 nums2 合併到 nums1 中,使得 num1 成爲一個有序數組。app
說明:dom
package com.cnblogs.mufasa.QA1_makeAhotDOU; import org.junit.Test; import java.util.Arrays; public class Solution4 { //1,普通的合併排序,算法就是O((n+m)log(n+m)),其中 public void merge1(int[] nums1, int m, int[] nums2, int n) { System.arraycopy(nums2, 0, nums1, m, n); Arrays.sort(nums1); SysPrint(nums1); } //2,新開闢地址空間逐項進行大小比較轉移 public void merge2(int[] nums1, int m, int[] nums2, int n) { int[] copy_nums1=new int[m]; System.arraycopy(nums1,0,copy_nums1,0,m);//nums1的大小是知足咱們要求的,可是其中的內容不必定夠 int p1=0,p2=0; int p=0; while (p1<m&&p2<n){ nums1[p++]=copy_nums1[p1]<nums2[p2]?copy_nums1[p1++]:nums2[p2++]; } if(p1<m){ System.arraycopy(copy_nums1,p1,nums1,p1+p2,m+n-p1-p2); }else { System.arraycopy(nums2,p2,nums1,p1+p2,m+n-p1-p2); } SysPrint(nums1); } private static void SysPrint(int[] nums1){ System.out.print("["+nums1[0]); for(int i=1;i<nums1.length;i++){ System.out.print(","+nums1[i]); } System.out.println("]"); } @Test public void test(){ int[] nums1={1,2,3,0,0,0}; // int[] nums2={4,5,6}; int[] nums2={2,5,6}; int m=3,n=3; // int[] nums1={0}; // int[] nums2={1}; // int m=0,n=1; merge1( nums1, m, nums2, n); merge2( nums1, m, nums2, n); } }
你將得到 K
個雞蛋,並可使用一棟從 1
到 N
共有 N
層樓的建築。ide
每一個蛋的功能都是同樣的,若是一個蛋碎了,你就不能再把它掉下去。
你知道存在樓層 F
,知足 0 <= F <= N
任何從高於 F
的樓層落下的雞蛋都會碎,從 F
樓層或比它低的樓層落下的雞蛋都不會破。
每次移動,你能夠取一個雞蛋(若是你有完整的雞蛋)並把它從任一樓層 X
扔下(知足 1 <= X <= N
)。
你的目標是確切地知道 F
的值是多少。
不管 F
的初始值如何,你肯定 F
的值的最小移動次數是多少?
package com.cnblogs.mufasa.QA1_makeAhotDOU; import org.junit.Test; import java.util.HashMap; import java.util.Map; public class Solution5 { //1,動態規劃加二分搜索 public int superEggDrop1(int K, int N) { return dp(K, N); } Map<Integer, Integer> memo = new HashMap(); public int dp(int K, int N) { if (!memo.containsKey(N * 100 + K)) { int ans; if (N == 0) ans = 0; else if (K == 1) ans = N; else { int lo = 1, hi = N; while (lo + 1 < hi) { int x = (lo + hi) / 2; int t1 = dp(K - 1, x - 1); int t2 = dp(K, N - x); if (t1 < t2) lo = x; else if (t1 > t2) hi = x; else lo = hi = x; } ans = 1 + Math.min(Math.max(dp(K - 1, lo - 1), dp(K, N - lo)), Math.max(dp(K - 1, hi - 1), dp(K, N - hi))); } memo.put(N * 100 + K, ans); } return memo.get(N * 100 + K); } //2,自底向上的dp算法 public int superEggDrop2(int K, int N) { //初始化dp的最原始記錄 int[] dp = new int[N+1]; for (int i = 0; i <= N; ++i) dp[i] = i; //逐步更新數據 for (int k = 2; k <= K; ++k) { int[] dp2 = new int[N+1]; int x = 1; for (int n = 1; n <= N; ++n) { while (x < n && Math.max(dp[x-1], dp2[n-x]) > Math.max(dp[x], dp2[n-x-1])) x++; dp2[n] = 1 + Math.max(dp[x-1], dp2[n-x]); } dp = dp2; } return dp[N]; } //3,遞歸調用法【參考信息論的知識】--失敗的方法,後續繼續剛啊 public int superEggDrop(int K, int N) { return recurEggDrop(K,N+1,true);//以個數爲準,true表示初始化判決 } private int recurEggDrop(int K,int N,boolean flag){ if(flag&&(K==1||N<=3)){ return N-1; }else if(!flag&&(K==1||N<=3)){ return N; } int pre=(N-1)/2; return Math.max(1+recurEggDrop( K-1, pre,true),1+recurEggDrop( K, pre+(N+1)%2,false)); } @Test public void test(){ // int K = 3, N = 14; // int K = 2, N = 2; // int K = 2, N = 3; int K = 2, N = 6; System.out.println(superEggDrop1(K,N)); } }
給定一個字符串,驗證它是不是迴文串,只考慮字母和數字字符,能夠忽略字母的大小寫。
package com.cnblogs.mufasa.QA1_String; import org.junit.Test; public class Solution1 { //LeetCode上耗時最短的算法 public boolean isPalindrome(String s) { if(s==null){ return false; }else if(s.length()<=1){ return true; } int i = 0; int j = s.length() - 1; char[] cs = s.toCharArray(); while(i < j){ if(!((cs[i] >= '0' && cs[i] <= '9') || (cs[i] >= 'A' && cs[i] <= 'Z') || (cs[i] >= 'a' && cs[i] <= 'z'))){//判斷不是元字符,直接移動光標便可,跳出本次循環 i++; continue; } if(!((cs[j] >= '0' && cs[j] <= '9') || (cs[j] >= 'A' && cs[j] <= 'Z') || (cs[j] >= 'a' && cs[j] <= 'z'))){ j--; continue; } if(cs[i] == cs[j]){//char相同,直接先後光標移動, i++; j--; continue; } if((cs[i] - cs[j] == 32 || cs[i]-cs[j] == -32) && cs[i] > '9' && cs[j] > '9'){//ignoreCase的手搖式方法 i++; j--; continue; } return false; } return true; } //使用到多於的函數來輔助進行判斷,①正則表達式;②toLowerCase public boolean isPalindrome1(String s) { s=s.replaceAll("\\W",""); s=s.toLowerCase(); int len=s.length(); for(int i=0;i<len/2;i++){ if(s.charAt(i)!=s.charAt(len-1-i)){ return false; } } return true; } @Test public void test(){ String str0="A man, a plan, a canal: Panama"; String str1="race a car"; System.out.println(isPalindrome(str0)); System.out.println(isPalindrome(str1)); } }
給定一個字符串 s,將 s 分割成一些子串,使每一個子串都是迴文串。
返回 s 全部可能的分割方案。
package com.cnblogs.mufasa.QA1_String; import org.junit.Test; import java.util.ArrayList; import java.util.List; public class Solution2 { //1,採用分治法求解的一種思路 public List<List<String>> partition(String s) { return partitionHelper(s, 0); } //遞歸&分治:大問題進行拆分化解爲相同原理的小問題,以後將結果合併 private List<List<String>> partitionHelper(String s, int start) { if (start == s.length()) {//內部是一個null值,退出的出口 List<String> list = new ArrayList<>(); List<List<String>> ans = new ArrayList<>(); ans.add(list); return ans; } List<List<String>> ans = new ArrayList<>(); for (int i = start; i < s.length(); i++) { if (isPalindrome(s.substring(start, i + 1))) {//當前切割後是迴文串才考慮 String left = s.substring(start, i + 1); //遍歷後邊字符串的全部結果,將當前的字符串加到頭部 for (List<String> l : partitionHelper(s, i + 1)) {//Recursive Node 很巧妙的一個步驟 l.add(0, left); ans.add(l); } } } return ans; } //判斷當前字符串是否爲迴文 private boolean isPalindrome(String s) { int i = 0; int j = s.length() - 1; while (i < j) { if (s.charAt(i) != s.charAt(j)) { return false; } i++; j--; } return true; } //2,優化分治算法,在判斷是否爲迴文的這一步驟中,咱們重複進行了不少次冗餘判斷,這個咱們能夠避免掉的 public List<List<String>> partition1(String s) { int length = s.length(); boolean[][] dp = new boolean[length][length]; for (int len = 1; len <= length; len++) { for (int i = 0; i <= s.length() - len; i++) { int j = i + len - 1; //要保證dp[i + 1][j - 1] 中 i + 1 <= j - 1 dp[i][j] = s.charAt(i) == s.charAt(j) && (len < 3 || dp[i + 1][j - 1]);//利用歷史信息優化計算 } } return partitionHelper(s, 0, dp); } private List<List<String>> partitionHelper(String s, int start, boolean[][] dp) { if (start == s.length()) { List<String> list = new ArrayList<>(); List<List<String>> ans = new ArrayList<>(); ans.add(list); return ans; } List<List<String>> ans = new ArrayList<>(); for (int i = start; i < s.length(); i++) { if (dp[start][i]) {//直接省略掉了重複判斷迴文的步驟 String left = s.substring(start, i + 1); for (List<String> l : partitionHelper(s, i + 1, dp)) { l.add(0, left); ans.add(l); } } } return ans; } //3,回溯法 public List<List<String>> partition2(String s) { boolean[][] dp = new boolean[s.length()][s.length()]; int length = s.length(); for (int len = 1; len <= length; len++) { for (int i = 0; i <= s.length() - len; i++) { dp[i][i + len - 1] = s.charAt(i) == s.charAt(i + len - 1) && (len < 3 || dp[i + 1][i + len - 2]); } } List<List<String>> ans = new ArrayList<>(); partitionHelper(s, 0, dp, new ArrayList<>(), ans); return ans; } private void partitionHelper(String s, int start, boolean[][] dp, List<String> temp, List<List<String>> res) { //到了空串就加到最終的結果中 if (start == s.length()) { res.add(new ArrayList<>(temp)); } //在不一樣位置切割 for (int i = start; i < s.length(); i++) { //若是是迴文串就加到結果中 if (dp[start][i]) { String left = s.substring(start, i + 1); temp.add(left); partitionHelper(s, i + 1, dp, temp, res); temp.remove(temp.size() - 1); } } } public static void printOut(List<List<String>> arrs){ System.out.println("["); for(List<String> list:arrs){ System.out.print("\t["+list.get(0)); for(String str:list.subList(1,list.size())){ System.out.print(","+str); } System.out.println("]"); } System.out.println("]"); } @Test public void test(){ String s="aabb"; // List<List<String>> arrs=partition(s); // List<List<String>> arrs=partition1(s); List<List<String>> arrs=partition2(s); printOut(arrs); } }
給定一個整數數組 nums
,找出一個序列中乘積最大的連續子序列(該序列至少包含一個數)。
給定一個整數數組 nums
,找到一個具備最大和的連續子數組(子數組最少包含一個元素),返回其最大和。
package com.cnblogs.mufasa.QA2_nums; import org.junit.Test; public class Solution1_1 { //動態規劃的一類題型,將歷史數據存入sum中與當前數據進行比較 public int maxSubArray(int[] nums) { int result = nums[0]; // 保存最大的結果 int sum = 0; // 保存當前的子序和 for (int num : nums) { if (sum > 0) { // sum是正數,意味着後面有機會再創新高,能夠繼續加 sum += num; } else { // sum是負的,還不如直接從當前位從新開始算,也比(負數+當前值)要大吧 sum = num; } result = Math.max(result, sum); // 每一步都更新最大值 } return result; } @Test public void test(){ int[] nums={-2,1,-3,4,-1,2,1,-5,4}; System.out.println(maxSubArray(nums)); } }
給定一組非負整數,從新排列它們的順序使之組成一個最大的整數。
package com.cnblogs.mufasa.QA7_sort_search; import org.junit.Test; import java.util.Arrays; public class Solution1 { //1,直接利用CompareTo進行排序 public String largestNumber1(int[] nums) { String[] arr=new String[nums.length]; for(int i=0;i<nums.length;i++){ arr[i]=""+nums[i]; } Arrays.sort(arr,(a,b)->{ String ab=a+b; String ba=b+a; int len=ab.length(); for(int i=0;i<len;i++){ int temp=ab.charAt(i)-ba.charAt(i); if(temp<0){ return 1; }else if(temp>0){ return -1; } } return 0; }); StringBuilder sb=new StringBuilder(); boolean flag=true; for(String temp:arr){ if(flag){ if(!temp.equals("0")){ sb.append(temp); flag=false; } }else { sb.append(temp); } } if(arr.length!=0&&sb.length()==0){ sb.append(""+0); } return sb.toString(); } //2,對以上代碼進行優化 public String largestNumber2(int[] nums){ String[] arrs = new String[nums.length]; for(int i =0; i < nums.length; i++){ arrs[i] = String.valueOf(nums[i]); } Arrays.sort(arrs, (a,b)->{ String ab=a+b; String ba=b+a; return -ab.compareTo(ba); }); StringBuilder sb = new StringBuilder(); for(String i : arrs){ sb.append(i); } String str=sb.toString(); if(str.startsWith("0")){ return "0"; } return str; } @Test public void test(){ // int[] nums={10,2}; int[] nums={3,30,9,34,5}; // int[] nums={0,0,0}; System.out.println(largestNumber2(nums)); } }
峯值元素是指其值大於左右相鄰值的元素。
給定一個輸入數組 nums
,其中 nums[i] ≠ nums[i+1]
,找到峯值元素並返回其索引。
數組可能包含多個峯值,在這種狀況下,返回任何一個峯值所在位置便可。
你能夠假設 nums[-1] = nums[n] = -∞
。
package com.cnblogs.mufasa.QA7_sort_search; import org.junit.Test; public class Solution3 { //1,遍歷法:時間複雜度爲O(n),很顯然不符合人家的要求 public int findPeakElement1(int[] nums) { int len=nums.length; int[] flag={0,0}; int loc=0; for(int i=0;i<len-1;i++){ flag[0]=flag[1]; if(nums[i]<nums[i+1]){ flag[1]=-1; loc=i+1; }else if(nums[i]>nums[i+1]){ flag[1]=1; } flag[1]=(nums[i]==nums[i+1]?0:(nums[i]<nums[i+1]?-1:1)); if(flag[0]==-1&&flag[1]==1){ return i; } } return loc; } //2,二分查找法求解 public int findPeakElement(int[] nums) { int left = 0, right = nums.length - 1; for (; left < right; ) { int mid = left + (right - left) / 2; if (nums[mid] > nums[mid + 1]) { right = mid; } else { left = mid + 1; } } return left; } @Test public void test(){ // int[] nums={1,2,1,3,5,6,4}; // int[] nums={1,2,3,1}; int[] nums={2,1}; // int[] nums={1,2}; System.out.println(findPeakElement(nums)); } }
nums
,將它從新排列成
nums[0] < nums[1] > nums[2] < nums[3]...
的順序。
給你一個無序的數組 nums
, 將該數字 原地 重排後使得 nums[0] <= nums[1] >= nums[2] <= nums[3]...
。
給定一個包含 n + 1 個整數的數組 nums,其數字都在 1 到 n 之間(包括 1 和 n),可知至少存在一個重複的整數。假設只有一個重複的整數,找出這個重複的數。
package com.cnblogs.mufasa.QA7_sort_search; import org.junit.Test; import java.util.Arrays; import java.util.HashSet; import java.util.Set; public class Solution4 { //1,遍歷法求解,時間複雜度爲O(n^2) 好像恰好知足複雜度要求 public int findDuplicate1(int[] nums) { int len=nums.length; for(int i=0;i<len-1;i++){ for(int j=i+1;j<len;j++){ if((nums[i]^nums[j])==0){ return nums[i]; } } } return -1; } //2,排序法,不符合題目要求的只讀限制條件 public int findDuplicate2(int[] nums) { Arrays.sort(nums); for (int i = 1; i < nums.length; i++) { if (nums[i] == nums[i-1]) { return nums[i]; } } return -1; } //3,開闢新空間處理,空間複雜度爲O(n),時間複雜度爲O(n),不知足空間複雜度O(1)的限制 public int findDuplicate3(int[] nums) { Set<Integer> seen = new HashSet<Integer>(); for (int num : nums) { if (seen.contains(num)) { return num; } seen.add(num); } return -1; } //4,弗洛伊德的烏龜和兔子(循環檢測) public int findDuplicate4(int[] nums) { int tortoise = nums[0]; int hare = nums[0]; do{ tortoise = nums[tortoise]; hare = nums[nums[hare]]; }while(tortoise!=hare); int p1=nums[0]; int p2=tortoise; while(p1!=p2){ p1 = nums[p1]; p2 = nums[p2]; } return p1; } @Test public void test(){ // int[] nums={3,1,3,4,2}; int[] nums={2,5,9,6,9,3,8,9,7,1}; System.out.println(findDuplicate4(nums)); } }
給定一個整數數組 nums,按要求返回一個新數組 counts。數組 counts 有該性質: counts[i]
的值是 nums[i]
右側小於 nums[i]
的元素的數量。
package com.cnblogs.mufasa.QA7_sort_search; import org.junit.Test; import org.w3c.dom.Node; import java.util.ArrayList; import java.util.LinkedList; import java.util.List; public class Solution5 { //1,暴力法,能夠求解,太low了,不想寫 //2,利用歷史數據進行更新迭代,比暴力法要好一些,可是複雜度仍是O(n^2) public List<Integer> countSmaller2(int[] nums) { List<Integer> list=new ArrayList<>(); List<Integer> queue=new ArrayList<>(nums.length); if(nums==null||nums.length==0){ return list; } int len=nums.length; list.add(0); queue.add(nums[len-1]); boolean flag=true; for(int i=len-2;i>=0;i--){ int cnt=len-i-1; int pre=nums[i]; int lenQ=queue.size(); for(int j=0;j<lenQ;j++){ if(pre<=queue.get(j)){//前面的數值有大於等於本數字的 cnt--; }else { flag=false; queue.add(j,pre); break; } } if(flag){ list.add(0,0); queue.add(pre); }else { list.add(0,cnt); flag=true; } } return list; } //3,在上面的基礎上添加二分查找法來進行性能優化,複雜度爲O(nlogn) public List<Integer> countSmaller3(int[] nums) { List<Integer> list=new ArrayList<>(); List<Integer> queue=new ArrayList<>(nums.length); if(nums==null||nums.length==0){ return list; } int len=nums.length; list.add(0); queue.add(nums[len-1]); boolean flag=true; for(int i=len-2;i>=0;i--){ int cnt=len-i-1; int pre=nums[i]; int lenQ=queue.size(); //這個部分更換爲二分查找法 int index=binarySearch(queue,pre); queue.add(index,pre); list.add(0,lenQ-index); } return list; } private static int binarySearch(List<Integer> arr,int target){//並非查找固定值,而是查找特定位置 if(arr.size()==1){ return (arr.get(0)<target?0:1); } int x=0,y=arr.size()-1,mid=1; while (x<y){ mid=(x+y)/2; int temp=arr.get(mid); if(temp<target){ y=mid; }else if(temp>target){ x=mid; }else { return mid; } } return y; } //4,經過二叉樹結構來完成 static int smallSum; private class TreeNode { int val; int count; TreeNode left; TreeNode right; TreeNode(int val) { this.val = val; this.count = 0; this.left = null; this.right = null; } } public List<Integer> countSmaller4(int[] nums) { int len = nums.length; List<Integer> result = new LinkedList(); if (len < 1) return result; TreeNode root = new TreeNode(nums[len - 1]); for (int i = len - 2; i >= 0; i--) { smallSum = 0; insert(root, new TreeNode(nums[i])); result.add(0, smallSum); } result.add(0); return result; } private void insert(TreeNode curr, TreeNode newNode) {//利用搜索二叉樹的結構 if (curr == null) return; if (newNode.val > curr.val) { smallSum += curr.count + 1; if (curr.right == null) curr.right = newNode; else insert(curr.right, newNode); }else { curr.count++; if (curr.left == null) curr.left = newNode; else insert(curr.left, newNode); } } @Test public void test(){ // int[] nums={10,5,4,3,2,1}; // List<Integer> arr=new ArrayList<>(); // for(int i:nums){ // arr.add(i); // } // int[] nums={5,2,6,1}; // int[] nums={}; int[] nums={26,78,27,100,33,67,90,23,66,5,38,7,35,23,52,22,83,51,98,69,81,32,78,28,94,13,2,97,3,76,99,51,9,21,84,66,65,36,100,41}; System.out.println(countSmaller3(nums)); // System.out.println(binarySearch(arr,5)); } } /* [10,27,10,35,12,22,28,8,19,2,12,2,9,6,12,5,17,9,19,12,14,6,12,5,12,3,0,10,0,7,8,4,0,0,4,3,2,0,1,0] [5,27,5,35,7,22,28,3,19,-8,11,-8,4,1,12,0,17,9,19,12,14,1,12,0,12,-3,0,10,0,7,8,4,0,0,4,3,2,0,1,0] */
須要進一步本身手撕一遍的問題:10.二、10.三、10.四、
給定一個二維平面,平面上有 n 個點,求最多有多少個點在同一條直線上。
package com.cnblogs.mufasa.QA10_math; import org.junit.Test; import java.util.HashMap; import java.util.Map; public class Solution2 { public int maxPoints(int[][] points) { int n = points.length; if (n == 0) return 0; if (n == 1) return 1; int res = 0; for (int i = 0; i < n - 1; i++) { Map<String, Integer> slope = new HashMap<>(); int repeat = 0; int tmp_max = 0; for (int j = i + 1; j < n; j++) { int dy = points[i][1] - points[j][1]; int dx = points[i][0] - points[j][0]; if (dy == 0 && dx == 0) { repeat++; continue; } int g = gcd(dy, dx); if (g != 0) { dy /= g; dx /= g; } String tmp = String.valueOf(dy) + "/" + String.valueOf(dx); slope.put(tmp, slope.getOrDefault(tmp, 0) + 1); tmp_max = Math.max(tmp_max, slope.get(tmp)); } res = Math.max(res, repeat + tmp_max + 1); } return res; } private int gcd(int dy, int dx) { if (dx == 0) return dy; else return gcd(dx, dy % dx); } @Test public void test(){ int[][] points={{1,1},{2,2},{3,3}}; System.out.println(maxPoints(points)); } }
給定兩個整數,分別表示分數的分子 numerator 和分母 denominator,以字符串形式返回小數。
若是小數部分爲循環小數,則將循環的部分括在括號內。
package com.cnblogs.mufasa.QA10_math; import org.junit.Test; import java.util.HashMap; import java.util.Map; public class Solution3 { //長除法 public String fractionToDecimal(int numerator, int denominator) { if (numerator == 0) { return "0"; } StringBuilder sb = new StringBuilder(); if (numerator < 0 ^ denominator < 0) {//判斷負數 sb.append("-"); } //轉換爲long類型數據 long dividend = Math.abs(Long.valueOf(numerator)); long divisor = Math.abs(Long.valueOf(denominator)); sb.append(String.valueOf(dividend / divisor)); long remainder = dividend % divisor; if (remainder == 0) {//只有整數部分 return sb.toString(); } sb.append(".");//上述不返回值,那麼就存在小數部分 Map<Long, Integer> map = new HashMap<>(); while (remainder != 0) { if (map.containsKey(remainder)) {//循環體部分數據 sb.insert(map.get(remainder), "("); sb.append(")"); break; } map.put(remainder, sb.length()); remainder *= 10; sb.append(String.valueOf(remainder / divisor)); remainder %= divisor; } return sb.toString(); } @Test public void test(){ int numerator = 1, denominator = 2; System.out.println(sbToDecimal(numerator,denominator)); } }
給定一個整數 n,返回 n! 結果尾數中零的數量。
package com.cnblogs.mufasa.QA10_math; import org.junit.Test; public class Solution4 { //1,暴力法直接忽略,不做爲討論 //2,數學推論:①查看10的倍數;②查看個位爲5與偶數成對出現的個數便可;注意這裏只查看尾數中的零的個數!!! public int trailingZeroes(int n) { int sum = n/5; int n1 = n; while(n1 / 5 != 0 && n1 >= 5) { n1 = n1/5; sum += n1/5; } return sum; } @Test public void test(){ int n=10; System.out.println(trailingZeroes(n)); } }
顛倒給定的 32 位無符號整數的二進制位。
package com.cnblogs.mufasa.QA10_math; import org.junit.Test; public class Solution5 { //1,先轉爲String,反轉後轉爲int public int reverseBits1(int n) { StringBuilder sb=new StringBuilder(Integer.toBinaryString(n)); int len=sb.length(); if(len<32){ for(int i=0;i<32-len;i++){ sb.insert(0,"0"); } } sb.reverse(); return binaryToInt(sb.toString()); } private static int binaryToInt(String binary) { if (binary == null) { System. out.println("can't input null !"); } if (binary.isEmpty()) { System. out.println("you input is Empty !" ); } int max = binary.length(); String new_binary = ""; if (max >= 2 && binary.startsWith("0")) { int position = 0; for (int i = 0; i < binary.length(); i++) { char a = binary.charAt(i); if (a != '0' ) { position = i; break; } } if (position == 0) { new_binary = binary.substring(max - 1, max); } else { new_binary = binary.substring(position, max); } } else { new_binary = binary; } int new_width = new_binary.length(); long result = 0; if (new_width < 32) { for (int i = new_width; i > 0; i--) { char c = new_binary.charAt(i - 1); int algorism = c - '0' ; result += Math. pow(2, new_width - i) * algorism; } } else if (new_width == 32) { for (int i = new_width; i > 1; i--) { char c = new_binary.charAt(i - 1); int algorism = c - '0' ; result += Math. pow(2, new_width - i) * algorism; } result += -2147483648; } int a = new Long(result).intValue(); return a; } //2,利用位運算進行處理,先向右移動到基底位,在向左移動到目標反轉位 public int reverseBits(int n) { int a=0; for(int i=0;i<32;i++){ a=a+((1&(n>>i))<<(31-i));//注意符號優先級 } return a; } @Test public void test(){ // int n=43261596; // int n=4294967293; // int n=-3; int n=43261596; System.out.println(reverseBits(n)); } }
編寫一個函數,輸入是一個無符號整數,返回其二進制表達式中數字位數爲 ‘1’ 的個數(也被稱爲漢明重量)。
package com.cnblogs.mufasa.QA10_math; import org.junit.Test; public class Solution6 { // you need to treat n as an unsigned value public int hammingWeight(int n) { int cnt=0; int pre=n; for(int i=0;i<32;i++){ if((pre&1)==1){ cnt++; } pre=pre>>1; } return cnt; } public int hammingWeight1(int n) { String str=Integer.toBinaryString(n); str=str.replaceAll("0",""); return str.length(); } @Test public void test(){ // int n=00000000000000000000000000001011; // int n=00000000000000000000000010000000; int n=-3; System.out.println(hammingWeight(n)); } }
統計全部小於非負整數 n 的質數的數量。
package com.cnblogs.mufasa.QA10_math; import org.junit.Test; import java.util.ArrayList; public class Solution7 { //1,能夠完成計算任務,可是計算超時 public int countPrimes1(int n) { ArrayList<Integer> primes=new ArrayList<>(); if(n<=2){ return 0; }else { primes.add(2); } boolean flag=true; for(int i=3;i<n;i++){ for(int j=0;j<primes.size();j++){ if(i%primes.get(j)==0){ flag=false; break; } } if(flag){ // System.out.print(i+","); primes.add(i); }else { flag=true; } } return primes.size(); } //2,厄拉多塞篩法 public int countPrimes2(int n){ if(n<=2){ return 0; } boolean[] arr=new boolean[n+1]; int cnt=0; for(int i=2;i<n;i++){ if(!arr[i]){ cnt++; int plus=2; int temp=plus*i; while (temp<n){ arr[temp]=true; plus++; temp=plus*i; } } } return cnt; } //3,至關於做弊的方法,把輸入樣例對應的輸出直接寫出來了 public int countPrimes(int n) { if (n == 10000) return 1229; if (n == 499979) return 41537; if (n == 999983) return 78497; if (n == 1500000) return 114155; int count = 0; loop: for(int i = 2; i < n; i++){ for(int j = 2; j * j <= i; j++){//平方小於便可 if(i % j == 0){ continue loop; } } count++; } return count; } @Test public void test(){ // int n=10; // int n=2; int n=499979; // System.out.println(countPrimes1(n)); System.out.println(countPrimes2(n)); // System.out.println(countPrimes(n)); } }
給定一個包含 0, 1, 2, ..., n
中 n 個數的序列,找出 0 .. n 中沒有出如今序列中的那個數。
一步步優化算法的過程,頗有成就感。
package com.cnblogs.mufasa.QA10_math; import org.junit.Test; import java.util.Arrays; public class Solution8 { //1,暴力法:先排序、在逐位判斷是否爲其地址值,不是的話就直接輸出當前地址值, // 所有都正確的話就直接輸出nums的長度值,至關於後面+1 //時間複雜度爲O(nlogn+n) public int missingNumber1(int[] nums) { int len=nums.length; Arrays.sort(nums); for(int i=0;i<len;i++){ if(nums[i]!=i){ return i; } } return len; } //2,開闢額外空間進行輔助,時間複雜度爲O(n+n) public int missingNumber2(int[] nums) { int len=nums.length; boolean[] arr=new boolean[len+1]; for(int i=0;i<len;i++){ arr[nums[i]]=true; } for(int i=0;i<len+1;i++){ if(!arr[i]){ return i; } } return 0; } //3,使用異或求解法!很優美的一種解決辦法,而且也不開闢大量的新空間,算法複雜度爲O(n) public int missingNumber(int[] nums) { int temp=0,len=nums.length; for(int i=0;i<len;i++){ temp^=i; temp^=nums[i]; } temp^=len; return temp; } @Test public void test(){ // int[] nums={9,6,4,2,3,5,7,0,1}; int[] nums={3,0,1}; System.out.println(missingNumber(nums)); } }
給定一個整數,寫一個函數來判斷它是不是 3 的冪次方。
package com.cnblogs.mufasa.QA10_math; import org.junit.Test; public class Solution9 { //1,暴力法:直接上手就是除 public boolean isPowerOfThree1(int n) { if(n<=0){ return false; } while (n!=0){ if(n==1){ return true; }else if(n%3!=0){ return false; }else { n/=3; } } return true; } //2,暴力法的基礎上更加,優雅的coding public boolean isPowerOfThree2(int n){ if(n<1) return false; while(n%3 == 0){ n /= 3; } return n == 1; } //3,還有其餘更加優雅的方法嗎?!! //還真有更加厲害的解法,很厲害,很贊 public boolean isPowerOfThree3(int n) { //3的階乘的int最大值與n取模,爲0表明是3的階乘 return (n>0 && 1162261467 % n == 0); } @Test public void test(){ // int n=45; // int n=2; int n=27; System.out.println(isPowerOfThree1(n)); System.out.println(isPowerOfThree2(n)); System.out.println(isPowerOfThree3(n)); } }