剑指Offer(java答案)(51-60)
51、數(shù)組中重復(fù)的數(shù)
題目描述 在一個長度為n的數(shù)組里的所有數(shù)字都在0到n-1的范圍內(nèi)。 數(shù)組中某些數(shù)字是重復(fù)的,但不知道有幾個數(shù)字是重復(fù)的。也不知道每個數(shù)字重復(fù)幾次。請找出數(shù)組中任意一個重復(fù)的數(shù)字。 例如,如果輸入長度為7的數(shù)組{2,3,1,0,2,5,3},那么對應(yīng)的輸出是重復(fù)的數(shù)字2或者3。
思路1:排序,時間復(fù)雜度O(NlogN)
思路2:Hash表,時間和空間復(fù)雜度都是O(N)
import java.util.HashMap; import java.util.Iterator; import java.util.Map.Entry; public class Solution {boolean duplicate(int numbers[],int length,int [] duplication) {HashMap<Integer, Integer> countMap = new HashMap<Integer, Integer>();if(length < 2||numbers==null){return false;}int j = 1;for(int i = 0;i < length;i++){if(countMap.get(numbers[i]) == null){j = 1;countMap.put(numbers[i], j);}else{j = countMap.get(numbers[i]);j++;countMap.put(numbers[i], j);}}Iterator iter = countMap.entrySet().iterator();while(iter.hasNext()){Entry<Integer, Integer> entry = (Entry<Integer, Integer>) iter.next();Integer key = entry.getKey();Integer val = countMap.get(key);if(val > 1){duplication[0] = key;return true;}}return false;} }復(fù)制代碼思路3:用Set集合,因為Set集合不允許有重復(fù)的,時間和空間復(fù)雜度都是O(N)
import java.util.Set; import java.util.HashSet; public class Solution {boolean duplicate(int numbers[], int length, int[] duplication) {if(length < 2||numbers==null){return false;}Set<Integer> ss = new HashSet<Integer>();for (int i = 0; i < numbers.length; i++) {if (ss.contains(numbers[i])) {duplication[0] = numbers[i];return true;} else {ss.add(numbers[i]);}}return false;} } 復(fù)制代碼思路4better:時間復(fù)雜度O(N),所有操作都是在輸入數(shù)組上進(jìn)行,所以不需要分配額外空間,空間復(fù)雜度為O(1)
[圖片上傳失敗...(image-c952f5-1558756468475)]
public class Solution {public boolean duplicate(int numbers[],int length,int [] duplication) {if(numbers==null||length<0)return false;for(int i = 0;i < length; i++){if(numbers[i]<0||numbers[i]>length-1)return false;}for(int i = 0;i< length;i++){while(numbers[i]!=i){if(numbers[i]==numbers[numbers[i]]){duplication[0] = numbers[i];return true;}else{//沒有找到,然后則交換,使該數(shù)到正確的位置去swap(numbers,i,numbers[i]);}}}return false;}//交換二數(shù)private void swap(int[]a, int i, int j){int temp = a[i];a[i] = a[j];a[j] = temp;} } 復(fù)制代碼52、構(gòu)建乘積數(shù)組
題目描述 給定一個數(shù)組A[0,1,...,n-1],請構(gòu)建一個數(shù)組B[0,1,...,n-1],其中B中的元素B[i]=A[0] * A[1] * ... * A[i-1]* A[i+1]* ...*A[n-1]。不能使用除法。
思路:1.計算前i - 1個元素的乘積,及后N - i個元素的乘積分別保存在兩個數(shù)組中
[圖片上傳失敗...(image-d5e569-1558756468476)]
import java.util.ArrayList; public class Solution {public int[] multiply(int[] A) {int len = A.length;int forword[] = new int[len];int backword[] = new int[len];int B[] = new int[len];forword[0] = 1;backword[0] = 1;for(int i = 1;i < len; i++){forword[i] = A[i - 1]*forword[i-1];backword[i] = A[len - i]*backword[i - 1];}for(int i = 0; i < len; i++){B[i] = forword[i] * backword[len - i -1];}return B;} } 復(fù)制代碼53、正則表達(dá)式匹配
題目描述 請實現(xiàn)一個函數(shù)用來匹配包括'.'和'* '的正則表達(dá)式。模式中的字符'.'表示任意一個字符,而'* ' 表示它前面的字符可以出現(xiàn)任意次(包含0次)。 在本題中,匹配是指字符串的所有字符匹配整個模式。例如,字符串"aaa"與模式"a.a"和"ab* ac* a"匹配,但是與"aa.a"和"ab*a"均不匹配
public class Solution {public boolean match(char[] str, char[] pattern) {if (str == null || pattern == null) {return false;}int strIndex = 0;int patternIndex = 0;return matchCore(str, strIndex, pattern, patternIndex); }public boolean matchCore(char[] str, int strIndex, char[] pattern, int patternIndex) {//str到尾,pattern到尾,匹配成功if (strIndex == str.length && patternIndex == pattern.length) {return true;}//str未到尾,pattern到尾,匹配失敗if (strIndex != str.length && patternIndex == pattern.length) {return false;}//str到尾,pattern未到尾(不一定匹配失敗,因為a*可以匹配0個字符)if (strIndex == str.length && patternIndex != pattern.length) {//只有pattern剩下的部分類似a*b*c*的形式,才匹配成功if (patternIndex + 1 < pattern.length && pattern[patternIndex + 1] == '*') {return matchCore(str, strIndex, pattern, patternIndex + 2);}return false;}//str未到尾,pattern未到尾if (patternIndex + 1 < pattern.length && pattern[patternIndex + 1] == '*') {if (pattern[patternIndex] == str[strIndex] || (pattern[patternIndex] == '.' && strIndex != str.length)) {//三種可能://1、模式串當(dāng)前字符出現(xiàn)0次,即*表示當(dāng)前字符出現(xiàn)0次,則str=str,pattern=pattern+2;//2、模式串當(dāng)前字符出現(xiàn)1次,即*表示當(dāng)前字符出現(xiàn)1次,則str=str+1,pattern=pattern+2;//3、模式串當(dāng)前字符出現(xiàn)2次或2次以上,即*表示當(dāng)前字符出現(xiàn)2次或以上,則str=str+1,pattern=pattern;return matchCore(str, strIndex, pattern, patternIndex + 2)//*匹配0個,跳過|| matchCore(str, strIndex + 1, pattern, patternIndex + 2)//*匹配1個,跳過|| matchCore(str, strIndex + 1, pattern, patternIndex);//*匹配1個,再匹配str中的下一個} else {//直接跳過*(*匹配到0個)//如果當(dāng)前字符不匹配,則只能讓*表示當(dāng)前字符出現(xiàn)0次,則str=str,pattern=pattern+2;return matchCore(str, strIndex, pattern, patternIndex + 2);}}//模式串下一字符不為*if (pattern[patternIndex] == str[strIndex] || (pattern[patternIndex] == '.' && strIndex != str.length)) {return matchCore(str, strIndex + 1, pattern, patternIndex + 1);}return false;} } 復(fù)制代碼54、表示數(shù)值的字符串
題目描述 請實現(xiàn)一個函數(shù)用來判斷字符串是否表示數(shù)值(包括整數(shù)和小數(shù))。例如,字符串"+100","5e2","-123","3.1416"和"-1E-16"都表示數(shù)值。 但是"12e","1a3.14","1.2.3","+-5"和"12e+4.3"都不是。
思路1:正則表達(dá)式
public class Solution {public boolean isNumeric(char[] str) {String string = String.valueOf(str);return string.matches("[\\+-]?[0-9]*(\\.[0-9]*)?([eE][\\+-]?[0-9]+)?");} } 復(fù)制代碼思路2:
public class Solution {boolean isNumeric(char[] s) {if (s.length == 0)return false;if ((s.length == 1) && (s[0] < '0' || s[0] > '9'))return false;if (s[0] == '+' || s[0] == '-') {if (s.length == 2 && (s[1] == '.'))return false;} else if ((s[0] < '0' || s[0] > '9') && s[0] != '.')return false;// 首位既不是符號也不是數(shù)字還不是小數(shù)點,當(dāng)然是falseint i = 1;while ((i < s.length) && (s[i] >= '0' && s[i] <= '9'))i++;if (i < s.length && s[i] == '.') {i++;// if(i>=s.length) return false;while ((i < s.length) && (s[i] >= '0' && s[i] <= '9'))i++;}if (i < s.length && (s[i] == 'e' || s[i] == 'E')) {i++;if ((i < s.length) && (s[i] == '+' || s[i] == '-')) {i++;if (i < s.length)while ((i < s.length) && (s[i] >= '0' && s[i] <= '9'))i++;elsereturn false;} else if (i < s.length) {while ((i < s.length) && (s[i] >= '0' && s[i] <= '9'))i++;} elsereturn false;}if (i < s.length)return false;return true;} } 復(fù)制代碼55、字符流中第一個不重復(fù)的字符
題目描述 請實現(xiàn)一個函數(shù)用來找出字符流中第一個只出現(xiàn)一次的字符。例如,當(dāng)從字符流中只讀出前兩個字符"go"時,第一個只出現(xiàn)一次的字符是"g"。當(dāng)從該字符流中讀出前六個字符“google"時,第一個只出現(xiàn)一次的字符是"l"。
import java.util.*; public class Solution {HashMap<Character, Integer> map=new HashMap();ArrayList<Character> list=new ArrayList<Character>();//Insert one char from stringstreampublic void Insert(char ch){if(map.containsKey(ch)){map.put(ch,map.get(ch)+1);}else{map.put(ch,1);}list.add(ch);}//return the first appearence once char in current stringstreampublic char FirstAppearingOnce(){ char c='#';for(char key : list){if(map.get(key)==1){c=key;break;}}return c;} } 復(fù)制代碼56、鏈表中環(huán)的入口結(jié)點
題目描述 一個鏈表中包含環(huán),請找出該鏈表的環(huán)的入口結(jié)點。
/*public class ListNode {int val;ListNode next = null;ListNode(int val) {this.val = val;} }*/ public class Solution {public ListNode EntryNodeOfLoop(ListNode pHead) {if (pHead == null || pHead.next == null)return null;// 先判斷是否有環(huán)ListNode n1 = pHead;// 走一步ListNode n2 = pHead;// 走兩步ListNode n = null;// 記錄n1,n2碰面的點while (n2 != null && n2.next != null) {n2 = n2.next.next;n1 = n1.next;if (n2 == n1) {n = n2;// 記錄碰頭節(jié)點break;}}// 求出環(huán)中節(jié)點數(shù)量int num = 0;ListNode temp = n;// n的鏡像do {temp = temp.next;num++;} while (temp != n);ListNode node1 = pHead;ListNode node2 = pHead;// node1先走num步,然后node1,node2同時走,碰頭的地方即入口節(jié)點for (int i = 0; i < num; i++) {node1 = node1.next;}int num1 = 0;while (node1 != node2) {node1 = node1.next;node2 = node2.next;num1++;}return node1;} } 復(fù)制代碼57、刪除鏈表中重復(fù)的結(jié)點
題目描述 在一個排序的鏈表中,存在重復(fù)的結(jié)點,請刪除該鏈表中重復(fù)的結(jié)點,重復(fù)的結(jié)點不保留,返回鏈表頭指針。 例如,鏈表1->2->3->3->4->4->5 處理后為 1->2->5
思路:重點是第一個也可能是重復(fù)的點,因此新建一個preNode節(jié)點保存前一個節(jié)點
/**public class ListNode {int val;ListNode next = null;ListNode(int val) {this.val = val;} } */ public class Solution {public ListNode deleteDuplication(ListNode pHead){if(pHead==null)return null;ListNode preNode = null;ListNode node = pHead;while(node!=null){ListNode nextNode = node.next;boolean needDelete = false;//判斷相鄰兩個點是否相等if(nextNode!=null&&nextNode.val==node.val){needDelete = true;}if(!needDelete){preNode = node;node = node.next;}else{int value = node.val;ListNode toBeDel = node;while(toBeDel!=null&&toBeDel.val == value){nextNode = toBeDel.next;toBeDel = nextNode;//此處不能少,找到第一個pHead,以后的preNode就不為null了if(preNode==null)pHead = nextNode;elsepreNode.next = nextNode;node = nextNode;}}}return pHead;} }復(fù)制代碼58、二叉樹的下一個結(jié)點
題目描述 給定一個二叉樹和其中的一個結(jié)點,請找出中序遍歷順序的下一個結(jié)點并且返回。注意,樹中的結(jié)點不僅包含左右子結(jié)點,同時包含指向父結(jié)點的指針。
思路:畫圖分析,考慮三種情況 [圖片上傳失敗...(image-af1795-1558756468476)]
/** public class TreeLinkNode {int val;TreeLinkNode left = null;TreeLinkNode right = null;TreeLinkNode parent= null;TreeLinkNode(int val) {this.val = val;} } */ public class Solution {TreeLinkNode GetNext(TreeLinkNode node){if(node==null) return null;if(node.right!=null){ //如果有右子樹,則找右子樹的最左節(jié)點node = node.right;while(node.left!=null) node = node.left;return node;}while(node.parent!=null){ //沒右子樹,則找第一個當(dāng)前節(jié)點是父節(jié)點左孩子的節(jié)點if(node.parent.left==node) return node.parent;node = node.parent;}return null; //退到了根節(jié)點仍沒找到,則返回null} } 復(fù)制代碼59、對稱的二叉樹
題目描述 請實現(xiàn)一個函數(shù),用來判斷一顆二叉樹是不是對稱的。注意,如果一個二叉樹同此二叉樹的鏡像是同樣的,定義其為對稱的。
/** public class TreeNode {int val = 0;TreeNode left = null;TreeNode right = null;public TreeNode(int val) {this.val = val;}} */ public class Solution {boolean isSymmetrical(TreeNode pRoot) { return isSymmetrical(pRoot,pRoot);}//定義兩個遍歷,一個前序遍歷,一個是和前序遍歷相反的,先右后左的遍歷boolean isSymmetrical(TreeNode pRoot1, TreeNode pRoot2) {if (pRoot1 == null && pRoot2 == null)return true;if (pRoot1 == null || pRoot2 == null)return false;if (pRoot1.val != pRoot2.val)return false;return isSymmetrical(pRoot1.left,pRoot2.right) && isSymmetrical(pRoot1.right, pRoot2.left);} } 復(fù)制代碼60、把二叉樹打印成多行
題目描述 從上到下按層打印二叉樹,同一層結(jié)點從左至右輸出。每一層輸出一行。
import java.util.*;/** public class TreeNode {int val = 0;TreeNode left = null;TreeNode right = null;public TreeNode(int val) {this.val = val;}} */ public class Solution {ArrayList<ArrayList<Integer> > Print(TreeNode pRoot) {ArrayList<ArrayList<Integer>> result = new ArrayList<ArrayList<Integer>>();if(pRoot == null){return result;}//使用隊列,先進(jìn)先出Queue<TreeNode> layer = new LinkedList<TreeNode>();ArrayList<Integer> layerList = new ArrayList<Integer>();layer.add(pRoot);int start = 0, end = 1;//start記錄本層打印了多少個,end記錄下一層要打印多少個while(!layer.isEmpty()){TreeNode cur = layer.remove();layerList.add(cur.val);//添加本行打印的List里start++;//每打印一個節(jié)點,就把此節(jié)點的下一層的左右節(jié)點加入隊列,并記錄下一層要打印的個數(shù)if(cur.left!=null){layer.add(cur.left); }if(cur.right!=null){layer.add(cur.right);}//本層打印完畢if(start == end){end = layer.size();start = 0;result.add(layerList);layerList = new ArrayList<Integer>();}}return result;} } 復(fù)制代碼聲明:此文章為本人原創(chuàng),如有轉(zhuǎn)載,請注明出處
如果您覺得有用,歡迎關(guān)注我的公眾號,我會不定期發(fā)布自己的學(xué)習(xí)筆記、AI資料、以及感悟,歡迎留言,與大家一起探索AI之路。
轉(zhuǎn)載于:https://juejin.im/post/5ce8c1f7f265da1bad56e0b0
總結(jié)
以上是生活随笔為你收集整理的剑指Offer(java答案)(51-60)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【CentOS 7笔记24】,实验中发生
- 下一篇: ?为什么要学这个技术(有什么优秀的地方,