現在也一月份了,春招的話金三銀四,要好好把握,想起我去年一月份的時候還在忙著看面試總結,這是我之前面試總結的知識點,一部分是網上down來的,一部分是蒐集的面試問題,應該是很全面了,問來問去基礎也就那些,無論是BAT等一線大廠或者其他不同的企業這些面試題目足夠了,再也有一些推薦的書單這個大家可以在網上找然後自行下載和也附上我的一些資料,具體的學習路線不用多說,自行Baidu即可,弄懂了這些面試常見問題,基礎的方面算是解決了,剩下的專案經驗還要注重平時積累,切忌臨時抱佛腳,很快就會露餡的。
網站推薦
http://gityuan.com/2016/01/09/java-memory/記憶體模型 http://www.guokr.com/post/114121/ Https握手 http://blog.csdn.net/laner0515/article/details/27692673/核心工作原理 http://www.cnblogs.com/fanzhidongyzby/p/4098546.html IO http://blog.csdn.net/sszgg2006/article/details/38664789 IO http://blog.csdn.net/forfuture3513/article/details/52445213 IO http://www.blogjava.net/bolo/archive/2015/01/20/422296.html 併發模型 http://blog.csdn.net/qq396229783/article/details/19924393 String http://jingyan.baidu.com/article/acf728fd2182e7f8e510a32e.html 中文編碼問題 http://www.cnblogs.com/200911/p/3965108.html 記憶體溢位解決方案 https://www.nowcoder.com/discuss/5683 spring問題 http://blog.csdn.net/u010425776/article/details/55006347 計算機網路 http://blog.csdn.net/hguisu/article/details/7445768/ Socket http://www.jb51.net/article/19024.htm SQL優化 http://www.cnblogs.com/coder2012/p/5309197.html 索引 http://www.360doc.com/content/14/0903/10/15077656_406704297.shtml redis設計與實現 http://blog.csdn.net/sinat_35512245/article/details/59056120 面試題總結網址
書單推薦
PS:這些書都是一些業內有名的書網上鍊接也比較多就不一一列舉了同一種型別的大家可以讀一兩本對照即可,這些我都粗略讀過,都是不錯的書籍,值得推薦,web方向尤其是一些關於大型網站技術架構方面一定要了解一下,可以在專案面吹水一下,感覺也是不錯的
面試題彙總
- 九種基本資料型別的大小,以及他們的封裝類。
- Switch能否用string做引數?
- equals與==的區別。
- Object有哪些公用方法?
- Java的四種引用,強弱軟虛,用到的場景
- Hashcode的作用。
- ArrayList、LinkedList、Vector的區別。
- String、StringBuffer與StringBuilder的區別。
- Map、Set、List、Queue、Stack的特點與用法。
- HashMap和HashTable的區別。
- HashMap和ConcurrentHashMap的區別,HashMap的底層原始碼。
- TreeMap、HashMap、LindedHashMap的區別。
- Collection包結構,與Collections的區別。
- try catch finally,try裡有return,finally還執行麼?
- Excption與Error包結構。OOM你遇到過哪些情況,SOF你遇到過哪些情況。
- Java物件導向的三個特徵與含義。
- Override和Overload的含義去區別。
- Interface與abstract類的區別。
- Static class 與non static class的區別。
- java多型的實現原理。
- 實現多執行緒的兩種方法:Thread與Runable。
- 執行緒同步的方法:sychronized、lock、reentrantLock等。
- 鎖的等級:方法鎖、物件鎖、類鎖。
- 寫出生產者消費者模式。
- ThreadLocal的設計理念與作用。
- ThreadPool用法與優勢。
- Concurrent包裡的其他東西:ArrayBlockingQueue、CountDownLatch等等。
- wait()和sleep()的區別。
- foreach與正常for迴圈效率對比。
- Java IO與NIO。
- 反射的作用於原理。
- 泛型常用特點,List能否轉為List。
- 解析XML的幾種方式的原理與特點:DOM、SAX、PULL。
- Java與C++對比。
- Java1.7與1.8新特性。
- 設計模式:單例、工廠、介面卡、責任鏈、觀察者等等。
- JNI的使用。 JVM
- 記憶體模型以及分割槽,需要詳細到每個區放什麼。
- 堆裡面的分割槽:Eden,survival from to,老年代,各自的特點。
- 物件建立方法,物件的記憶體分配,物件的訪問定位。
- GC的兩種判定方法:引用計數與引用鏈。
- GC的三種收集方法:標記清除、標記整理、複製演算法的原理與特點,分別用在什麼地方,如果讓你優化收集方法,有什麼思路?
- GC收集器有哪些?CMS收集器與G1收集器的特點。
- Minor GC與Full GC分別在什麼時候發生?
- 幾種常用的記憶體除錯工具:jmap、jstack、jconsole。
- 類載入的五個過程:載入、驗證、準備、解析、初始化。
- 雙親委派模型:Bootstrap ClassLoader、Extension ClassLoader、ApplicationClassLoader。
- 分派:靜態分派與動態分派。 作業系統
- 程式和執行緒的區別。
- 死鎖的必要條件,怎麼處理死鎖。
- Window記憶體管理方式:段儲存,頁儲存,段頁儲存。
- 程式的幾種狀態。
- IPC幾種通訊方式。
- 什麼是虛擬記憶體。
- 虛擬地址、邏輯地址、線性地址、實體地址的區別。 TCP/IP
- OSI與TCP/IP各層的結構與功能,都有哪些協議。
- TCP與UDP的區別。
- TCP報文結構。 4.TCP的三次握手與四次揮手過程,各個狀態名稱與含義,TIMEWAIT的作用。
- TCP擁塞控制
- TCP滑動視窗與回退N針協議。
- Http的報文結構。
- Http的狀態碼含義。
- Http request的幾種型別。
- Http1.1和Http1.0的區別
- Http怎麼處理長連線。
- Cookie與Session的作用於原理。
- 電腦上訪問一個網頁,整個過程是怎麼樣的:DNS、HTTP、TCP、OSPF、IP、ARP。
- Ping的整個過程。ICMP報文是什麼。
- C/S模式下使用socket通訊,幾個關鍵函式。
- IP地址分類。
- 路由器與交換機區別。 資料結構與演算法
- 連結串列與陣列。
- 佇列和棧,出棧與入棧。
- 連結串列的刪除、插入、反向。
- 字串操作。
- Hash表的hash函式,衝突解決方法有哪些。
- 各種排序:冒泡、選擇、插入、希爾、歸併、快排、堆排、桶排、基數的原理、平均時間複雜度、最壞時間複雜度、空間複雜度、是否穩定。
- 快排的partition函式與歸併的Merge函式。
- 對冒泡與快排的改進。
- 二分查詢,與變種二分查詢。
- 二叉樹、B+樹、AVL樹、紅黑樹、哈夫曼樹。
- 二叉樹的前中後續遍歷:遞迴與非遞迴寫法,層序遍歷演算法。
- 圖的BFS與DFS演算法,最小生成樹prim演算法與最短路徑Dijkstra演算法。
- KMP演算法。
- 排列組合問題。
- 動態規劃、貪心演算法、分治演算法。(一般不會問到)
- 大資料處理:類似10億條資料找出最大的1000個數.........等等 物件導向和麵向過程的區別 面試問題(來自BAT等企業):
IO模型有哪些? 程式執行緒的區別 不同作業系統實現程式有什麼區別 gc演算法,回收器有哪些 ACID,事務隔離機制 syn在方法上和程式碼塊有什麼不同 memcached和其他nosql的區別 解釋mvc threadlocal解釋 volatile的作用 堆和棧的區別和聯絡 tcp和udp的不同之處 tcp如何保證可靠的 陣列和連結串列的區別 排序演算法應用場景 lucene全文檢索原理
動態規劃 spring事務 記憶體執行緒隔離 sleep()wait 三次握手兩次回收 S1和S2 RuntimeException HashMap中hash future Callable clone 負載因子 二叉樹遍歷 vector 回溯法 B-Tree 與B+Tree struts和spring HttpServlet容器響應Web客戶請求流程如下: 1)Web客戶向Servlet容器發出Http請求; 2)Servlet容器解析Web客戶的Http請求; 3)Servlet容器建立一個HttpRequest物件,在這個物件中封裝Http請求資訊; 4)Servlet容器建立一個HttpResponse物件; 5)Servlet容器呼叫HttpServlet的service方法,這個方法中會根據request的Method來判斷具體是執行doGet還是doPost,把HttpRequest和HttpResponse物件作為service方法的引數傳給HttpServlet物件; 6)HttpServlet呼叫HttpRequest的有關方法,獲取HTTP請求資訊; 7)HttpServlet呼叫HttpResponse的有關方法,生成響應資料; 8)Servlet容器把HttpServlet的響應結果傳給Web客戶。
doGet() 或 doPost() 是建立HttpServlet時需要覆蓋的方法. java.util.concourrent join 連結串列相交 判斷迴文字串 spring和struts 詞頻統計
集合類以及集合框架;HashMap與HashTable實現原理,執行緒安全性,hash衝突及處理演算法;ConcurrentHashMap
程式和執行緒的區別;多執行緒與執行緒池
資料一致性如何保證;Synchronized關鍵字,類鎖,方法鎖,重入鎖
同步的方法;多程式開發以及多程式應用場景
伺服器只提供資料接收介面,在多執行緒或多程式條件下,如何保證資料的有序到達
ThreadLocal原理,實現及如何保證Local屬性
String StringBuilder StringBuffer對比
介面與回撥;回撥的原理;寫一個回撥demo;
泛型原理,舉例說明;解析與分派
抽象類與介面的區別;應用場景;抽象類是否可以沒有方法和屬性
靜態屬性和靜態方法是否可以被繼承?是否可以被重寫?原因
修改物件A的equals方法的簽名,那麼使用HashMap存放這個物件例項的時候,會呼叫哪個equals方法
資料結構與演算法
堆和棧在記憶體中的區別是什麼(資料結構方面以及實際實現方面)
最快的排序演算法是哪個?給阿里2萬多名員工按年齡排序應該選擇哪個演算法?堆和樹的區別;寫出快排程式碼;連結串列逆序程式碼
求1000以內的水仙花數以及40億以內的水仙花數
子串包含問題(KMP 演算法)寫程式碼實現
萬億級別的兩個URL檔案A和B,如何求出A和B的差集C,(Bit對映->hash分組->多檔案讀寫效率->磁碟定址以及應用層面對定址的優化)
寫出你所知道的排序演算法及時空複雜度,穩定性
百度POI中如何試下查詢最近的商家功能(座標映象+R樹) 死鎖的四個必要條件
常見編碼方式;utf-8編碼中的中文佔幾個位元組;int型幾個位元組
實現一個Json解析器(可以通過正則提高速度)
MVC MVP MVVM; 常見的設計模式;寫出觀察者模式的程式碼
TCP的3次握手和四次揮手;TCP與UDP的區別
HTTP協議;HTTP1.0與2.0的區別;HTTP報文結構
手寫程式碼
兩個數加起來合為s 輸入一個遞增排序的陣列和一個數字S,在陣列中查詢兩個數,使得他們的和正好是S,如果有多對數字的和等於S,輸出兩個數的乘積最小的。 import java.util.ArrayList; public class Solution { public ArrayList FindNumbersWithSum(int [] array,int sum) { ArrayList result=new ArrayList(); if(array==null||array.length==0){ return result; } int i=0; int j=array.length-1;
while(i!=j){
if(array[i]+array[j]==sum){
result.add(array[i]);
result.add(array[j]);
return result;
}
else if(array[i]+array[j]>sum){
j--;
}
else{
i++;
}
}
return result;
}
複製程式碼
}
3.連結串列中環的入口結點 public class Solution {
public ListNode EntryNodeOfLoop(ListNode pHead)
{
ListNode slow=pHead;
ListNode fast=pHead;
while(fast.next!=null&&slow.next!=null){
fast=fast.next.next;
slow=slow.next;
if(slow==fast){
fast=pHead;
while(fast!=slow){
fast=fast.next;
slow=slow.next;
}
if(slow==fast){
return slow;
}
}
}
return null;
}
複製程式碼
}
4.全排列 public ArrayList permutation(String str){ char[] chars=str.toCharArray(); char[] arrs=new char[chars.length]; int []book=new int[chars.length];
dfs(strs,0);
}
peivate ArrayList dfs(char[] strs,step){
if(step==strs.length){ String str=""; for(int i=0;i<arrs.length;i++){
str=str+arrs[i];
複製程式碼
} return str; } for(int i=0;i<strs.length;i++){ if(book[i]==0){ arrs[step]=strs[i]; book[i]=1;
dfs(strs,step+1);
book[i]=0; }
} }
import java.util.*;
public class Solution { private char [] seqs; private Integer [] book; //用於結果去重 private HashSet result = new HashSet(); /** * 輸入一個字串,按字典序列印出該字串中字元的所有排列。 * 例如輸入字串abc,則列印出由字元a,b,c * 所能排列出來的所有字串abc,acb,bac,bca,cab和cba。 結果請按字母順序輸出。 * 輸入一個字串,長度不超過9(可能有字元重複),字元只包括大小寫字母。 * @param str * @return */ public ArrayList Permutation(String str) { ArrayList arrange = new ArrayList(); if(str == null || str.isEmpty()) return arrange; char[] strs = str.toCharArray(); seqs = new char[strs.length]; book = new Integer[strs.length]; for (int i = 0; i < book.length; i++) { book[i] = 0; } dfs(strs, 0); arrange.addAll(result); Collections.sort(arrange); return arrange; }
/**
* 深度遍歷法
*/
private void dfs(char[] arrs, int step){
//走完所有可能 記錄排列
if(arrs.length == step){
String str = "";
for (int i = 0; i < seqs.length; i++) {
str += seqs[i];
}
result.add(str);
return; //返回上一步
}
//遍歷整個序列,嘗試每一種可能
for (int i = 0; i < arrs.length; i++) {
//是否走過
if(book[i] == 0){
seqs[step] = arrs[i];
book[i] = 1;
//下一步
dfs(arrs, step + 1);
//走完最後一步 後退一步
book[i] = 0;
}
}
}
複製程式碼
}
回溯法 import java.util.*; public class Solution { public ArrayList Permutation(String str) { ArrayList re = new ArrayList(); if (str == null || str.length() == 0) { return re; } HashSet set = new HashSet(); fun(set, str.toCharArray(), 0); re.addAll(set); Collections.sort(re); return re; } void fun(HashSet re, char[] str, int k) { if (k == str.length) { re.add(new String(str)); return; } for (int i = k; i < str.length; i++) { swap(str, i, k); fun(re, str, k + 1); swap(str, i, k); } } void swap(char[] str, int i, int j) { if (i != j) { char t = str[i]; str[i] = str[j]; str[j] = t; } } }
5.二叉樹層次遍歷 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 { public ArrayList PrintFromTopToBottom(TreeNode root) { ArrayList level=new ArrayList();
if(root==null){
return level;
}
Queue <TreeNode> bfs=new LinkedList<TreeNode>();
bfs.offer(root);
while(!bfs.isEmpty()){
TreeNode r=bfs.poll();
level.add(r.val);
if(r.left!=null){
bfs.offer(r.left);
}
if(r.right!=null){
bfs.offer(r.right);
}
}
return level;
}
複製程式碼
}
6.用兩個棧實現佇列 public class Queue { private Stack stack1; private Stack stack2;
public Queue() {
複製程式碼
stack1=new Stack(); stack2=new Stack(); }
public void Stack1toStack2(){
while (! stack1.empty()) {
複製程式碼
stack2.push(stack1.pop()); } } public void push(int element) { stack1.push(element);
}
public int pop() {
if(stack2.size()==0){
Stack1toStack2();
}
return stack2.pop();
}
public int top() {
if(stack2.size()==0){
Stack1toStack2();
}
return stack2.peek();
}
複製程式碼
}
7.順時針列印矩陣 layer=(Math.min(m,n)-1)/2+1;
for(int i=0;i<layer;i++){ for(k=i;k<-i;k++)從左到右 for(j=i;j<n-i;j++ )從右上到右下 for(k=m-i-2;k>=i&&(n-i-1!=i);k--) for(j=n-i-2;(j>=i)&&(m-i-1!=i);j--) }
import java.util.ArrayList; public class Solution { public ArrayList printMatrix(int [][] array) { ArrayList result = new ArrayList (); if(array.length==0) return result; int n = array.length,m = array[0].length; if(m==0) return result; int layers = (Math.min(n,m)-1)/2+1;//這個是層數 for(int i=0;i<layers;i++){ for(int k = i;k<m-i;k++) result.add(array[i][k]);//左至右 for(int j=i+1;j<n-i;j++) result.add(array[j][m-i-1]);//右上至右下 for(int k=m-i-2;(k>=i)&&(n-i-1!=i);k--) result.add(array[n-i-1][k]);//右至左 for(int j=n-i-2;(j>i)&&(m-i-1!=i);j--) result.add(array[j][i]);//左下至左上 } return result;
}
複製程式碼
}
8.鏡面二叉樹 public class Solution { public void Mirror(TreeNode root) {
if(root!=null){
TreeNode temp=root.right;
root.right=root.left;
root.left=temp;
Mirror(root.left);
Mirror(root.right);
}
複製程式碼
} }
9.揹包問題 本題是典型的01揹包問題,每種型別的物品最多隻能選擇一件。參考前文 Knapsack 中總結的解法,這個題中可以將揹包的 size 理解為傳統揹包中的重量; 題目問的是能達到的最大 size, 故可將每個揹包的 size 類比為傳統揹包中的價值。 考慮到陣列索引從0開始,故定義狀態bp[i + 1][j]為前 i 個物品中選出重量不超過j時總價值的最大值。 狀態轉移方程則為分A[i] > j 與否兩種情況考慮。初始化均為0,相當於沒有放任何物品。 Java
public class Solution { /** * @param m: An integer m denotes the size of a backpack * @param A: Given n items with size A[i] * @return: The maximum size */ public int backPack(int m, int[] A) { if (A == null || A.length == 0) return 0;
final int M = m;
final int N = A.length;
int[][] bp = new int[N + 1][M + 1];
for (int i = 0; i < N; i++) {
for (int j = 0; j <= M; j++) {
if (A[i] > j) {
bp[i + 1][j] = bp[i][j];
} else {
bp[i + 1][j] = Math.max(bp[i][j], bp[i][j - A[i]] + A[i]);
}
}
}
return bp[N][M];
}
複製程式碼
}
10.堆排序 package edu.princeton.cs.algs4;
/**
-
The {@code Heap} class provides a static methods for heapsorting
-
an array.
-
-
For additional documentation, see Section 2.4 of
-
Algorithms, 4th Edition by Robert Sedgewick and Kevin Wayne.
-
@author Robert Sedgewick
-
@author Kevin Wayne */ public class Heap {
// This class should not be instantiated. private Heap() { }
/**
- Rearranges the array in ascending order, using the natural order.
- @param pq the array to be sorted */ public static void sort(Comparable[] pq) { int n = pq.length; for (int k = n/2; k >= 1; k--) sink(pq, k, n); while (n > 1) { exch(pq, 1, n--); sink(pq, 1, n); } }
/*************************************************************************** * Helper functions to restore the heap invariant. ***************************************************************************/
private static void sink(Comparable[] pq, int k, int n) {
while (2*k <= n) {
int j = 2*k;
if (j < n && less(pq, j, j+1)) j++;
if (!less(pq, k, j)) break;
exch(pq, k, j);
k = j;
}
}
複製程式碼
/*************************************************************************** * Helper functions for comparisons and swaps. * Indices are "off-by-one" to support 1-based indexing. ***************************************************************************/ private static boolean less(Comparable[] pq, int i, int j) { return pq[i-1].compareTo(pq[j-1]) < 0; }
private static void exch(Object[] pq, int i, int j) {
Object swap = pq[i-1];
pq[i-1] = pq[j-1];
pq[j-1] = swap;
}
// is v < w ?
private static boolean less(Comparable v, Comparable w) {
return v.compareTo(w) < 0;
}
複製程式碼
/*************************************************************************** * Check if array is sorted - useful for debugging. ***************************************************************************/ private static boolean isSorted(Comparable[] a) { for (int i = 1; i < a.length; i++) if (less(a[i], a[i-1])) return false; return true; }
// print array to standard output
private static void show(Comparable[] a) {
for (int i = 0; i < a.length; i++) {
StdOut.println(a[i]);
}
}
/**
* Reads in a sequence of strings from standard input; heapsorts them;
* and prints them to standard output in ascending order.
*
* @param args the command-line arguments
*/
public static void main(String[] args) {
String[] a = StdIn.readAllStrings();
Heap.sort(a);
show(a);
assert isSorted(a);
}
複製程式碼
}
11.歸併排序 public class Solution { /** * @param A an integer array * @return void */ public void sortIntegers2(int[] A) { // use a shared temp array, the extra memory is O(n) at least int[] temp = new int[A.length]; mergeSort(A, 0, A.length - 1, temp); }
private void mergeSort(int[] A, int start, int end, int[] temp) {
if (start >= end) {
return;
}
int left = start, right = end;
int mid = (start + end) / 2;
mergeSort(A, start, mid, temp);
mergeSort(A, mid+1, end, temp);
merge(A, start, mid, end, temp);
}
private void merge(int[] A, int start, int mid, int end, int[] temp) {
int left = start;
int right = mid+1;
int index = start;
// merge two sorted subarrays in A to temp array
while (left <= mid && right <= end) {
if (A[left] < A[right]) {
temp[index++] = A[left++];
} else {
temp[index++] = A[right++];
}
}
while (left <= mid) {
temp[index++] = A[left++];
}
while (right <= end) {
temp[index++] = A[right++];
}
// copy temp back to A
for (index = start; index <= end; index++) {
A[index] = temp[index];
}
}
複製程式碼
}
12.連結串列倒數第k個結點 快慢指標,注意最開始 head==null||k<=0的判斷和 if(fastpointer.next==null){ return dummy; }的判斷 public class Solution { public ListNode FindKthToTail(ListNode head,int k) { ListNode dummy=null; if(head==null||k<=0){ return dummy; } ListNode fastpointer=head; ListNode slowpointer=head;
int i=0; while(i<k-1){ if(fastpointer.next==null){ return dummy; } fastpointer=fastpointer.next; i++; }
while(fastpointer.next!=null){ fastpointer=fastpointer.next; slowpointer=slowpointer.next; }
return slowpointer; } }
13.反轉連結串列 public class Solution { public ListNode ReverseList(ListNode head) { ListNode next=null; ListNode pre=null;
while(head!=null){
next=head.next;
head.next=pre;
pre=head;
head=next;
}
return pre;
}
複製程式碼
}
14.合併兩個排序的連結串列 public class Solution { public ListNode Merge(ListNode list1,ListNode list2) {
ListNode dummy=new ListNode(0);
ListNode result=dummy;
while(list1!=null&&list2!=null){
if(list1.val<list2.val){
result.next=list1;
list1=list1.next;
}
else{
result.next=list2;
list2=list2.next;
}
result=result.next;
}
if (list1 != null) {
result.next = list1;
} else {
result.next = list2;
}
return dummy.next;
}
複製程式碼
}
15.連續子陣列的最大和 public class Solution { public int FindGreatestSumOfSubArray(int[] array) { if(array.length==0){ return 0; }
int result=array[0];
int sum=array[0];
for(int i=1;i<array.length;i++){
if(sum>=0){
sum=sum+array[i];
}
if(sum<0){
sum=array[i];
}
if(sum>result){
result=sum;
}
}
return result;
}
複製程式碼
}
16.把陣列排成最小的數 輸入一個正整數陣列,把陣列裡所有數字拼接起來排成一個數,列印能拼接出的所有數字中最小的一個。 例如輸入陣列{3,32,321},則列印出這三個數字能排成的最小數字為321323。 import java.util.ArrayList; import java.util.*; public class Solution {
public String PrintMinNumber(int [] numbers) {
if(numbers.length==0||numbers==null){
return "";
}
String[] str=new String[numbers.length];
StringBuilder sb=new StringBuilder();
for(int i=0;i<numbers.length;i++){
str[i]=String.valueOf(numbers[i]);
}
Arrays.sort(str,new Comparator<String>(){
public int compare(String s1, String s2) {
String c1 = s1 + s2;
String c2 = s2 + s1;
return c1.compareTo(c2);
}
});
for(int i = 0; i < str.length; i++){
sb.append(str[i]);
}
return sb.toString();
}
複製程式碼
}
17.兩個連結串列的第一個公共結點 //方法一:運用HasnMap的特性 import java.util.HashMap; public class Solution { public ListNode FindFirstCommonNode(ListNode pHead1, ListNode pHead2) { ListNode current1 = pHead1; ListNode current2 = pHead2;
HashMap<ListNode, Integer> hashMap = new HashMap<ListNode, Integer>();
while (current1 != null) {
hashMap.put(current1, null);
current1 = current1.next;
}
while (current2 != null) {
if (hashMap.containsKey(current2))
return current2;
current2 = current2.next;
}
return null;
}
複製程式碼
}
//方法2:
public ListNode FindFirstCommonNodeII(ListNode pHead1, ListNode pHead2) { ListNode current1 = pHead1;// 連結串列1 ListNode current2 = pHead2;// 連結串列2 if (pHead1 == null || pHead2 == null) return null; int length1 = getLength(current1); int length2 = getLength(current2); // 兩連表的長度差
// 如果連結串列1的長度大於連結串列2的長度
if (length1 >= length2) {
int len = length1 - length2;
// 先遍歷連結串列1,遍歷的長度就是兩連結串列的長度差
while (len > 0) {
current1 = current1.next;
len--;
}
}
// 如果連結串列2的長度大於連結串列1的長度
else if (length1 < length2) {
int len = length2 - length1;
// 先遍歷連結串列1,遍歷的長度就是兩連結串列的長度差
while (len > 0) {
current2 = current2.next;
len--;
}
}
//開始齊頭並進,直到找到第一個公共結點
while(current1!=current2){
current1=current1.next;
current2=current2.next;
}
return current1;
}
// 求指定連結串列的長度
public static int getLength(ListNode pHead) {
int length = 0;
ListNode current = pHead;
while (current != null) {
length++;
current = current.next;
}
return length;
}
18.二叉樹深度
複製程式碼
import java.util.Queue; import java.util.LinkedList;
public class Solution { public int TreeDepth(TreeNode pRoot) { if(pRoot == null){ return 0; } Queue queue = new LinkedList(); queue.add(pRoot); int depth = 0, count = 0, nextCount = 1; while(queue.size()!=0){ TreeNode top = queue.poll(); count++; if(top.left != null){ queue.add(top.left); } if(top.right != null){ queue.add(top.right); } if(count == nextCount){ nextCount = queue.size(); count = 0; depth++; } } return depth; } } 遞迴寫法,比較簡單,不解釋:
import java.lang.Math; public class Solution { public int TreeDepth(TreeNode pRoot) { if(pRoot == null){ return 0; } int left = TreeDepth(pRoot.left); int right = TreeDepth(pRoot.right); return Math.max(left, right) + 1; } }
19.和為S的序列 import java.util.ArrayList; /* *初始化small=1,big=2; *small到big序列和小於sum,big++;大於sum,small++; *當small增加到(1+sum)/2是停止 */ public class Solution { public ArrayList<ArrayList> FindContinuousSequence(int sum) { ArrayList<ArrayList> lists=new ArrayList<ArrayList>(); if(sum<=1){return lists;} int small=1; int big=2; while(small!=(1+sum)/2){ //當small==(1+sum)/2的時候停止 int curSum=sumOfList(small,big); if(curSum==sum){ ArrayList list=new ArrayList(); for(int i=small;i<=big;i++){ list.add(i); } lists.add(list); small++;big++; }else if(curSum<sum){ big++; }else{ small++; } } return lists; }
public int sumOfList(int head,int leap){ //計算當前序列的和
int sum=head;
for(int i=head+1;i<=leap;i++){
sum+=i;
}
return sum;
}
複製程式碼
}
20.約瑟夫環 class Solution { public: int LastRemaining_Solution(unsigned int n, unsigned int m) {
if(n <= 0 && m <= 0) return -1; //蛋疼的特殊條件
int t = 0;
for(int i = 2; i <= n; i++)
t = (t + m) % i;
return t;
}
複製程式碼
}; /* 約瑟夫問題 遞推公式 讓f[i]為i個人玩遊戲報m退出最後的勝利者的編號,最後的結果自然是f[n] 服了 f[1] = 0; f[i] = (f[i - 1] + m) mod i;
因為遞推,所以可以不用儲存狀態 程式碼如下
*/
/約瑟夫問題,求遞推公式,每輪的序列中最後出序列的數都是同一個/ public int LastRemaining_Solution(int n,int m) { if(n < 1 || m < 1) return -1; if(n == 1){ return 0; } return (LastRemaining_Solution(n-1, m)+m)%n; }
21.刪除連結串列中重複的結點 public static ListNode deleteDuplication(ListNode pHead) {
ListNode first = new ListNode(-1);//設定一個trick
first.next = pHead;
ListNode p = pHead;
ListNode last = first;
while (p != null && p.next != null) {
if (p.val == p.next.val) {
int val = p.val;
while (p!= null&&p.val == val)
p = p.next;
last.next = p;
} else {
last = p;
p = p.next;
}
}
return first.next;
}
22.之字形列印二叉樹
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{
public ArrayList<ArrayList> Print(TreeNode pRoot) {
ArrayList<ArrayList> result = new ArrayList<ArrayList>();
if(pRoot == null){
return result;
}
boolean leftToRight = true;
Queue layer = new LinkedList();
ArrayList layerList = new ArrayList();
layer.add(pRoot);
int start = 0, end = 1;
while(!layer.isEmpty()){
TreeNode cur = layer.remove();
layerList.add(cur.val);
start++;
if(cur.left!=null){
layer.add(cur.left);
}
if(cur.right!=null){
layer.add(cur.right);
}
if(start == end){
end = layer.size();
start = 0;
if(!leftToRight){
result.add(reverse(layerList));
}else{
result.add(layerList);
}
leftToRight = !leftToRight;
layerList = new ArrayList();
}
}
return result;
}
private ArrayList reverse(ArrayList layerList) {
int length = layerList.size();
ArrayList reverseList = new ArrayList();
for(int i = length-1; i >= 0;i--){
reverseList.add(layerList.get(i));
}
return reverseList;
}
}
23.二叉樹的下一個結點 /* public class TreeLinkNode { int val; TreeLinkNode left = null; TreeLinkNode right = null; TreeLinkNode next = null; (next指向父節點) TreeLinkNode(int val) { this.val = val; } } */ public class Solution { public TreeLinkNode GetNext(TreeLinkNode pNode) { if(pNode.right!=null){ pNode=pNode.right; while(pNode.left!=null){ pNode=pNode.left; }
return pNode;
}
else{
if(pNode.next.left==pNode){
return pNode.next;
}
else{
while(pNode.next.left!=pNode){
pNode=pNode.next;
}
return pNode;
}
}
}
複製程式碼
} 上面只過了25%,缺少判斷是否是根節點,最後一個return 應該是pNode.next public class Solution { TreeLinkNode GetNext(TreeLinkNode pNode) { if(pNode == null){ return null; } if(pNode.right != null){ pNode = pNode.right; while(pNode.left != null){ pNode = pNode.left; } return pNode; } while(pNode.next != null){ //非根節點 if(pNode == pNode.next.left) return pNode.next; pNode = pNode.next; } return null; } }
24.二叉搜尋樹第k個節點 給定一顆二叉搜尋樹,請找出其中的第k小的結點。例如, 5 / \ 3 7 /\ /\ 2 4 6 8 中,按結點數值大小順序第三個結點的值為4。 import java.util.Stack; public class Solution { //中序遞迴 int count = 0; TreeNode KthNode(TreeNode pRoot, int k) { if(count > k || pRoot == null) return null; TreeNode p = pRoot; Stack LDRStack = new Stack(); TreeNode kthNode = null; while(p != null || !LDRStack.isEmpty()){ while(p != null){ LDRStack.push(p); p = p.left; } TreeNode node = LDRStack.pop(); System.out.print(node.val+","); count++; if(count == k){ kthNode = node; } p = node.right; } return kthNode; } }
25.有一棵無窮大的滿二叉樹,其結點按根結點一層一層地從左往右依次編號,根結點編號為1。現在有兩個結點a,b。請設計一個演算法,求出a和b點的最近公共祖先的編號。 給定兩個int a,b。為給定結點的編號。請返回a和b的最近公共祖先的編號。注意這裡結點本身也可認為是其祖先。 //思路:滿二叉樹的子節點與父節點之間的關係為root = child / 2 //利用這個關係,如果a != b,就讓其中的較大數除以2, 如此迴圈知道a == b, //即是原來兩個數的最近公共祖先 //程式碼如下: class LCA { public: int getLCA(int a, int b) { // write code here while(a != b) { if(a > b) a /= 2; else b /= 2; } return a; } }
26.輸入一顆二叉樹和一個整數,列印出二叉樹中結點值的和為輸入整數的所有路徑。路徑定義為從樹的根結點開始往下一直到葉結點所經過的結點形成一條路徑。 import java.util.ArrayList; import java.util.Stack; public class Solution { public ArrayList<ArrayList> FindPath(TreeNode root, int target) { ArrayList<ArrayList> pathList= new ArrayList<ArrayList>(); if(root==null) return pathList; Stack stack=new Stack(); FindPath(root,target,stack,pathList ); return pathList;
}
private void FindPath(TreeNode root, int target,
Stack<Integer> path,
ArrayList<ArrayList<Integer>> pathList) {
if(root==null)
return;
if(root.left==null&&root.right==null){
if(root.val==target){
ArrayList<Integer> list=
new ArrayList<Integer>();
for(int i:path){
list.add(new Integer(i));
}
list.add(new Integer(root.val));
pathList.add(list);
}
}
else{
path.push(new Integer(root.val));
FindPath(root.left, target-root.val, path, pathList);
FindPath(root.right, target-root.val, path, pathList);
path.pop();
}
}
複製程式碼
}
27.對於一個字串,請設計一個演算法,判斷其是否為一個合法的括號串。 給定一個字串A和它的長度n,請返回一個bool值代表它是否為一個合法的括號串。 測試樣例: "(()())",6 返回:true 測試樣例: "()a()()",7 返回:false 測試樣例: "()(()()",7 返回:false
//1.非遞迴,使用棧結構 public boolean chkParenthesis(String A, int n) { // write code here /* * 1.碰到")"開始彈出棧頂的"(",如果此時棧為空,則返回false * 2.碰到其他內容直接返回false * 3.字串結尾時,棧非空返回false */ Stack lefts = new Stack(); if(A == null || A.length() != n){ return false; } for(int i = 0; i < n; i++){ if(A.charAt(i) == '('){ lefts.push(A.charAt(i)); }else if(A.charAt(i) == ')'){ if(lefts.empty()){ return false; }else{ lefts.pop(); } }else{ return false; } } if(!lefts.empty()){ return false; }else{ return true; } }
28.有兩個用連結串列表示的整數,每個結點包含一個數位。這些數位是反向存放的,也就是個位排在連結串列的首部。編寫函式對這兩個整數求和,並用連結串列形式返回結果。
複製程式碼
給定兩個連結串列ListNode* A,ListNode* B,請返回A+B的結果(ListNode*)。 測試樣例: {1,2,3},{3,2,1} 返回:{4,4,4}
public class Plus { public ListNode plusAB(ListNode a, ListNode b) { if (a == null) { return b; } if (b == null) { return a; } ListNode p1 = a, p2 = b; ListNode head = new ListNode(0); ListNode p = head; int sum = 0; while (p1 != null || p2 != null || sum != 0) { if (p1 != null) { sum += p1.val; p1 = p1.next; } if (p2 != null) { sum += p2.val; p2 = p2.next; } p.next = new ListNode(sum % 10); sum /= 10; p = p.next; } return head.next; } }
29.[程式設計題]連結串列分割 編寫程式碼,以給定值x為基準將連結串列分割成兩部分,所有小於x的結點排在大於或等於x的結點之前 給定一個連結串列的頭指標 ListNode* pHead,請返回重新排列後的連結串列的頭指標。注意:分割以後保持原來的資料順序不變。 思路
設定兩個連結串列頭,遍歷原連結串列,一個追加小數連結串列,一個追加大數連結串列,最後將小數連結串列粘到大數連結串列前邊即為結果。
class Partition { public: ListNode* partition(ListNode* head, int x) { if(head == nullptr){ return nullptr; }//if ListNode *smallList = new ListNode(-1); ListNode *bigList = new ListNode(-1); ListNode *ps = smallList,*pb = bigList,*cur = head; while(cur){ if(cur->val < x){ ps->next = cur; ps = cur; }//if else{ pb->next = cur; pb = cur; }//else cur = cur->next; }//while pb->next = nullptr; ps->next = bigList->next; return smallList->next; } }
30.樹轉換為連結串列 有一個類似結點的資料結構TreeNode,包含了val屬性和指向其它結點的指標。其可以用來表示二叉查詢樹(其中left指標表示左兒子,right指標表示右兒子)。 請編寫一個方法,將二叉查詢樹轉換為一個連結串列,其中二叉查詢樹的資料結構用TreeNode實現,連結串列的資料結構用ListNode實現。 給定二叉查詢樹的根結點指標root,請返回轉換成的連結串列的頭指標。
Solution: 利用中序遍歷,提供遞迴和非遞迴版本。
//Method 1: //遞迴
ListNode dummy=new ListNode(0);
ListNode tail=dummy;
public ListNode treeToList(TreeNode root) {
// write code here
if(root==null) return null;
treeToList(root.left);
tail.next=new ListNode(root.val);
tail=tail.next;
treeToList(root.right);
return dummy.next;
}
// Method 2: iterator
public ListNode treeToList(TreeNode root) {
// write code here
if(root==null) return null;
ListNode dummy=new ListNode(0);
ListNode tail=dummy;
Stack<TreeNode> stack=new Stack<TreeNode>();
while(root!=null || !stack.isEmpty()){
複製程式碼
while(root!=null){ stack.push(root); root=root.left; }
root=stack.pop();
tail.next=new ListNode(root.val);
tail=tail.next;
root=root.right;
}
return dummy.next;
}
31.陣列中的逆序對
在陣列中的兩個數字,如果前面一個數字大於後面的數字,則這兩個數字組成一個逆序對。
輸入一個陣列,求出這個陣列中的逆序對的總數P。並將P對1000000007取模的結果輸出。 即輸出P%1000000007
參考《劍指offer》用歸併排序的思想, 時間複雜度O(nlogn)
複製程式碼
int InversePairs(vector data) { int length = data.size(); return mergeSort(data, 0, length-1); }
int mergeSort(vector<int>& data, int start, int end) {
// 遞迴終止條件
if(start >= end) {
return 0;
}
// 遞迴
int mid = (start + end) / 2;
int leftCounts = mergeSort(data, start, mid);
int rightCounts = mergeSort(data, mid+1, end);
// 歸併排序,並計算本次逆序對數
vector<int> copy(data); // 陣列副本,用於歸併排序
int foreIdx = mid; // 前半部分的指標
int backIdx = end; // 後半部分的指標
int counts = 0; // 記錄本次逆序對數
int idxCopy = end; // 輔助陣列的下標
while(foreIdx>=start && backIdx >= mid+1) {
if(data[foreIdx] > data[backIdx]) {
copy[idxCopy--] = data[foreIdx--];
counts += backIdx - mid;
} else {
copy[idxCopy--] = data[backIdx--];
}
}
while(foreIdx >= start) {
copy[idxCopy--] = data[foreIdx--];
}
while(backIdx >= mid+1) {
copy[idxCopy--] = data[backIdx--];
}
for(int i=start; i<=end; i++) {
data[i] = copy[i];
}
return (leftCounts+rightCounts+counts);
}
複製程式碼
31.反轉單詞順序 //翻轉str從s到e的部分 void ReverseWord(string &str, int s, int e) { while(s < e) swap(str[s++], str[e--]); }
string ReverseSentence(string str) {
ReverseWord(str, 0, str.size() - 1); //先整體翻轉
int s = 0, e = 0;
int i = 0;
while(i < str.size())
{
while(i < str.size() && str[i] == ' ') //空格跳過
i++;
e = s = i; //記錄單詞的第一個字元的位置
while(i < str.size() && str[i] != ' ') //不是空格 找單詞最後一個字元的位置
{
i++;
e++;
}
ReverseWord(str, s, e - 1); //區域性翻轉
}
return str;
}
32.調整陣列順序使奇數位於偶數前面
輸入一個整數陣列,實現一個函式來調整該陣列中數字的順序,
使得所有的奇數位於陣列的前半部分,所有的偶數位於位於陣列的後半部分,並保證奇數和奇數,偶數和偶數之間的相對位置不變。
public void reOrderArray2(int [] a) {
if(a==null||a.length==0)
return;
int i = 0,j;
while(i<a.length){
while(i<a.length&&!isEven(a[i]))
i++;
j = i+1;
while(j<a.length&&isEven(a[j]))
j++;
if(j<a.length){
int tmp = a[j];
for (int j2 = j-1; j2 >=i; j2--) {
a[j2+1] = a[j2];
}
a[i++] = tmp;
}else{// 查詢失敗
break;
}
}
複製程式碼
} boolean isEven(int n){ if(n%2==0) return true; return false; }
//兩個思路吧,第一個思路:類似冒泡演算法,前偶後奇數就交換: class Solution { public: void reOrderArray(vector &array) {
for (int i = 0; i < array.size();i++)
{
for (int j = array.size() - 1; j>i;j--)
{
if (array[j] % 2 == 1 && array[j - 1]%2 == 0) //前偶後奇交換
{
swap(array[j], array[j-1]);
}
}
}
}
複製程式碼
};
//第二個思路:再建立一個陣列 class Solution{ public: void reOrderArray(vector &array) {
vector<int> array_temp;
vector<int>::iterator ib1, ie1;
ib1 = array.begin();
for (; ib1 != array.end();){ //遇見偶數,就儲存到新陣列,同時從原陣列中刪除
if (*ib1 % 2 == 0) {
array_temp.push_back(*ib1);
ib1 = array.erase(ib1);
}
else{
ib1++;
}
}
vector<int>::iterator ib2, ie2;
ib2 = array_temp.begin();
ie2 = array_temp.end();
for (; ib2 != ie2; ib2++) //將新陣列的數新增到老陣列
{
array.push_back(*ib2);
}
}
複製程式碼
};
33.最長公共子串 Given two strings, find the longest common substring. Return the length of it. Note The characters in substring should occur continiously in original string. This is different with subsequnce.
public class Solution { /** * @param A, B: Two string. * @return: the length of the longest common substring. */ public int longestCommonSubstring(String A, String B) { // state: f[i][j] is the length of the longest lcs // ended with A[i - 1] & B[j - 1] in A[0..i-1] & B[0..j-1] int n = A.length(); int m = B.length(); int[][] f = new int[n + 1][m + 1];
// initialize: f[i][j] is 0 by default
// function: f[i][j] = f[i - 1][j - 1] + 1 or 0
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
if (A.charAt(i - 1) == B.charAt(j - 1)) {
f[i][j] = f[i - 1][j - 1] + 1;
} else {
f[i][j] = 0;
}
}
}
// answer: max{f[i][j]}
int max = 0;
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
max = Math.max(max, f[i][j]);
}
}
return max;
}
複製程式碼
}
34.找出二叉樹中和值最大的路徑 Given a binary tree, find the maximum path sum. The path may start and end at any node in the tree.
For example: Given the below binary tree, 1 / \ 2 3 Return 6.
public class Solution { private class ResultType { // singlePath: 從root往下走到任意點的最大路徑,這條路徑可以不包含任何點 // maxPath: 從樹中任意到任意點的最大路徑,這條路徑至少包含一個點 int singlePath, maxPath; ResultType(int singlePath, int maxPath) { this.singlePath = singlePath; this.maxPath = maxPath; } }
private ResultType helper(TreeNode root) {
if (root == null) {
return new ResultType(0, Integer.MIN_VALUE);
}
// Divide
ResultType left = helper(root.left);
ResultType right = helper(root.right);
// Conquer
int singlePath = Math.max(left.singlePath, right.singlePath) + root.val;
singlePath = Math.max(singlePath, 0);
int maxPath = Math.max(left.maxPath, right.maxPath);
maxPath = Math.max(maxPath, left.singlePath + right.singlePath + root.val);
return new ResultType(singlePath, maxPath);
}
public int maxPathSum(TreeNode root) {
ResultType result = helper(root);
return result.maxPath;
}
複製程式碼
}
// Version 2: // SinglePath也定義為,至少包含一個點。 public class Solution { /** * @param root: The root of binary tree. * @return: An integer. */ private class ResultType { int singlePath, maxPath; ResultType(int singlePath, int maxPath) { this.singlePath = singlePath; this.maxPath = maxPath; } }
private ResultType helper(TreeNode root) {
if (root == null) {
return new ResultType(Integer.MIN_VALUE, Integer.MIN_VALUE);
}
// Divide
ResultType left = helper(root.left);
ResultType right = helper(root.right);
// Conquer
int singlePath =
Math.max(0, Math.max(left.singlePath, right.singlePath)) + root.val;
int maxPath = Math.max(left.maxPath, right.maxPath);
maxPath = Math.max(maxPath,
Math.max(left.singlePath, 0) +
Math.max(right.singlePath, 0) + root.val);
return new ResultType(singlePath, maxPath);
}
public int maxPathSum(TreeNode root) {
ResultType result = helper(root);
return result.maxPath;
}
複製程式碼
}
35.hashMap public class HashMap<K,V> extends AbstractMap<K,V> implements Map<K,V>, Cloneable, Serializable {
private static final long serialVersionUID = 362498820763181265L;
/**
* The default initial capacity - MUST be a power of two.
*/
static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16
/**
* The maximum capacity, used if a higher value is implicitly specified
* by either of the constructors with arguments.
* MUST be a power of two <= 1<<30.
*/
static final int MAXIMUM_CAPACITY = 1 << 30;
/**
* The load factor used when none specified in constructor.
*/
static final float DEFAULT_LOAD_FACTOR = 0.75f;
/**
* The bin count threshold for using a tree rather than list for a
* bin. Bins are converted to trees when adding an element to a
* bin with at least this many nodes. The value must be greater
* than 2 and should be at least 8 to mesh with assumptions in
* tree removal about conversion back to plain bins upon
* shrinkage.
*/
static final int TREEIFY_THRESHOLD = 8;
/**
* The bin count threshold for untreeifying a (split) bin during a
* resize operation. Should be less than TREEIFY_THRESHOLD, and at
* most 6 to mesh with shrinkage detection under removal.
*/
static final int UNTREEIFY_THRESHOLD = 6;
/**
* The smallest table capacity for which bins may be treeified.
* (Otherwise the table is resized if too many nodes in a bin.)
* Should be at least 4 * TREEIFY_THRESHOLD to avoid conflicts
* between resizing and treeification thresholds.
*/
static final int MIN_TREEIFY_CAPACITY = 64;
/**
* Basic hash bin node, used for most entries. (See below for
* TreeNode subclass, and in LinkedHashMap for its Entry subclass.)
*/
/**
* Computes key.hashCode() and spreads (XORs) higher bits of hash
* to lower. Because the table uses power-of-two masking, sets of
* hashes that vary only in bits above the current mask will
* always collide. (Among known examples are sets of Float keys
* holding consecutive whole numbers in small tables.) So we
* apply a transform that spreads the impact of higher bits
* downward. There is a tradeoff between speed, utility, and
* quality of bit-spreading. Because many common sets of hashes
* are already reasonably distributed (so don't benefit from
* spreading), and because we use trees to handle large sets of
* collisions in bins, we just XOR some shifted bits in the
* cheapest possible way to reduce systematic lossage, as well as
* to incorporate impact of the highest bits that would otherwise
* never be used in index calculations because of table bounds.
*/
static final int hash(Object key) {
int h;
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
* capacity and load factor.
*
* @param initialCapacity the initial capacity
* @param loadFactor the load factor
* @throws IllegalArgumentException if the initial capacity is negative
* or the load factor is nonpositive
*/
public HashMap(int initialCapacity, float loadFactor) {
if (initialCapacity < 0)
throw new IllegalArgumentException("Illegal initial capacity: " +
initialCapacity);
if (initialCapacity > MAXIMUM_CAPACITY)
initialCapacity = MAXIMUM_CAPACITY;
if (loadFactor <= 0 || Float.isNaN(loadFactor))
throw new IllegalArgumentException("Illegal load factor: " +
loadFactor);
this.loadFactor = loadFactor;
this.threshold = tableSizeFor(initialCapacity);
}
複製程式碼
/** * Returns the value to which the specified key is mapped, * or {@code null} if this map contains no mapping for the key. * *
More formally, if this map contains a mapping from a key * {@code k} to a value {@code v} such that {@code (key==null ? k==null : * key.equals(k))}, then this method returns {@code v}; otherwise * it returns {@code null}. (There can be at most one such mapping.) * *
A return value of {@code null} does not necessarily * indicate that the map contains no mapping for the key; it's also * possible that the map explicitly maps the key to {@code null}. * The {@link #containsKey containsKey} operation may be used to * distinguish these two cases. * * @see #put(Object, Object) */ public V get(Object key) { Node<K,V> e; return (e = getNode(hash(key), key)) == null ? null : e.value; }
/** * Implements Map.get and related methods * * @param hash hash for key * @param key the key * @return the node, or null if none */ final Node<K,V> getNode(int hash, Object key) { Node<K,V>[] tab; Node<K,V> first, e; int n; K k; if ((tab = table) != null && (n = tab.length) > 0 && (first = tab[(n - 1) & hash]) != null) { if (first.hash == hash && // always check first node ((k = first.key) == key || (key != null && key.equals(k)))) return first; if ((e = first.next) != null) { if (first instanceof TreeNode) return ((TreeNode<K,V>)first).getTreeNode(hash, key); do { if (e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k)))) return e; } while ((e = e.next) != null); } } return null; }
public V put(K key, V value) { return putVal(hash(key), key, value, false, true); }
/** * Implements Map.put and related methods * * @param hash hash for key * @param key the key * @param value the value to put * @param onlyIfAbsent if true, don't change existing value * @param evict if false, the table is in creation mode. * @return previous value, or null if none */ final V putVal(int hash, K key, V value, boolean onlyIfAbsent, boolean evict) { Node<K,V>[] tab; Node<K,V> p; int n, i; if ((tab = table) == null || (n = tab.length) == 0) n = (tab = resize()).length; if ((p = tab[i = (n - 1) & hash]) == null) tab[i] = newNode(hash, key, value, null); else { Node<K,V> e; K k; if (p.hash == hash && ((k = p.key) == key || (key != null && key.equals(k)))) e = p; else if (p instanceof TreeNode) e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value); else { for (int binCount = 0; ; ++binCount) { if ((e = p.next) == null) { p.next = newNode(hash, key, value, null); if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st treeifyBin(tab, hash); break; } if (e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k)))) break; p = e; } } if (e != null) { // existing mapping for key V oldValue = e.value; if (!onlyIfAbsent || oldValue == null) e.value = value; afterNodeAccess(e); return oldValue; } } ++modCount; if (++size > threshold) resize(); afterNodeInsertion(evict); return null; }
public V remove(Object key) { Node<K,V> e; return (e = removeNode(hash(key), key, null, false, true)) == null ? null : e.value; }
/**
* Implements Map.remove and related methods
*
* @param hash hash for key
* @param key the key
* @param value the value to match if matchValue, else ignored
* @param matchValue if true only remove if value is equal
* @param movable if false do not move other nodes while removing
* @return the node, or null if none
*/
final Node<K,V> removeNode(int hash, Object key, Object value,
boolean matchValue, boolean movable) {
Node<K,V>[] tab; Node<K,V> p; int n, index;
if ((tab = table) != null && (n = tab.length) > 0 &&
(p = tab[index = (n - 1) & hash]) != null) {
Node<K,V> node = null, e; K k; V v;
if (p.hash == hash &&
((k = p.key) == key || (key != null && key.equals(k))))
node = p;
else if ((e = p.next) != null) {
if (p instanceof TreeNode)
node = ((TreeNode<K,V>)p).getTreeNode(hash, key);
else {
do {
if (e.hash == hash &&
((k = e.key) == key ||
(key != null && key.equals(k)))) {
node = e;
break;
}
p = e;
} while ((e = e.next) != null);
}
}
if (node != null && (!matchValue || (v = node.value) == value ||
(value != null && value.equals(v)))) {
if (node instanceof TreeNode)
((TreeNode<K,V>)node).removeTreeNode(this, tab, movable);
else if (node == p)
tab[index] = node.next;
else
p.next = node.next;
++modCount;
--size;
afterNodeRemoval(node);
return node;
}
}
return null;
}
}
36.第一個只出現一次的字元
import java.util.*;
複製程式碼
public class Solution {
HashMap<Character, Integer> map = new HashMap<>();
public int FirstNotRepeatingChar(String str) {
if (str==null)return -1;
int length = str.length();
int chars[]=new int[256];
for(int i = 0;i<length;i++) {
if(map.containsKey(str.charAt(i))){
int value = map.get(str.charAt(i));
map.put(str.charAt(i),value+1);
}else{
map.put(str.charAt(i),1);
chars[str.charAt(i)]=i;
}
}
for(int i = 0;i<length;i++){
if(map.get(str.charAt(i))==1)
return chars[str.charAt(i)];
}
return -1;
}
複製程式碼
}
37.二維陣列查詢 在一個二維陣列中,每一行都按照從左到右遞增的順序排序,每一列都按照從上到下遞增的順序排序。 請完成一個函式,輸入這樣的一個二維陣列和一個整數,判斷陣列中是否含有該整數。
思路:首先我們選擇從左下角開始搜尋, (為什麼不從左上角開始搜尋,左上角向右和向下都是遞增,那麼對於一個點,對於向右和向下會產生一個岔路;如果我們選擇從左下腳開始搜尋的話, 如果大於就向右,如果小於就向下)。 public class Solution { public boolean Find(int [][] array,int target) { int len = array.length-1; int i = 0; while((len >= 0)&& (i < array[0].length)){ if(array[len][i] > target){ len--; }else if(array[len][i] < target){ i++; }else{ return true; } } return false; } }
38.LRU CACHE
public int get(int key) {
if( !hs.containsKey(key)) {
return -1;
}
// remove current
Node current = hs.get(key);
current.prev.next = current.next;
current.next.prev = current.prev;
// move current to tail
move_to_tail(current);
return hs.get(key).value;
}
public void set(int key, int value) {
if( get(key) != -1) {
hs.get(key).value = value;
return;
}
if (hs.size() == capacity) {
hs.remove(head.next.key);
head.next = head.next.next;
head.next.prev = head;
}
Node insert = new Node(key, value);
hs.put(key, insert);
move_to_tail(insert);
}
private void move_to_tail(Node current) {
current.prev = tail.prev;
tail.prev = current;
current.prev.next = current;
current.next = tail;
}
複製程式碼
}
39.大資料的top k 40.100個降序陣列,每組500個數,找到前3000大的數