標籤(空格分隔):筆記java
java其實已經將不少底層的數據結構進行了封裝,雖然工做用不到,可是筆試和麪試問的仍是比較頻繁的,並且這種面試題仍是直接手撕代碼,故專門總結一下。面試
1.1 鏈表(Linked list)數組
是一種常見的基礎數據結構,是一種線性表,可是並不會按線性的順序存儲數據,而是在每個節點裏存到下一個節點的指針(Pointer)。使用鏈表結構能夠克服數組鏈表須要預先知道數據大小的缺點,鏈表結構能夠充分利用計算機內存空間,實現靈活的內存動態管理。可是鏈表失去了數組隨機讀取的優勢,同時鏈表因爲增長告終點的指針域,空間開銷比較大。數據結構
1.2 單向鏈表(Single-Linked List)ide
2.1 設計一個接口,定義鏈表須要哪些操做(已經過驗證,放心用)函數
public interface ILinkedList { //添加元素 boolean addItems(Object obj); //刪除元素 boolean deleteItems(Object obj); //刪除頭元素 boolean deleteheadItems(); //查找 Object findItems(Object obj); //返回長度 int length(); //展現全部元素 void display(); //判斷是否爲空 boolean isEmpty(); }
2.2 定義一個單鏈表,實現上述接口的操做(已經過驗證,放心使用)測試
public class NewSingleList implements ILinkedList{ private int size;//鏈表長度 private Node head;//鏈表的頭結點,由於是成員變量,默認爲null // //定義一個成員內部類Node,包含頭部數據和next指向的對象 public class Node{ private Object data; private Node next; public Node(Object data, Node next) { this.data = data; this.next = next; } } //添加 @Override public boolean addItems(Object obj) { Node n1=new Node(obj,null); if(isEmpty()) { head=n1; size++; return true; } else { n1.next=head;//頭插法,從頭部插入,新插入的節點做爲新的head head=n1; size++; return false; } } //刪除元素 @Override public boolean deleteItems(Object obj) { if(isEmpty()) { return false; } if(head.data.equals(obj)) { deleteheadItems();//調用刪除頭部元素的函數 return true; } //定義當前節點的前一個節點(初始的時候下面兩個起點相同,可是循環一遍以後位置就變了,能夠本身試試) Node previous=head; Node current=head;//定義當前節點 while(current!=null) { if(current.data.equals(obj)) { previous.next=current.next;//刪除核心代碼 size--; return true; } else { previous=current; current=current.next; } } return false; } //刪除頭部元素 @Override public boolean deleteheadItems() { if(isEmpty()) { return false; } else { head=head.next; size--; return true; } } //查找 @Override public Object findItems(Object obj) { if(isEmpty()) {return false;} Node tmp=head; while(tmp!=null) { if(tmp.data.equals(obj)) {return true;} else { tmp=tmp.next; } } return false; } //返回鏈表長度 @Override public int length() { return size; } //展現元素 @Override public void display() { Node tmp=head; while(tmp!=null) { System.out.println(tmp.data); tmp=tmp.next; } } //判斷是否爲空 @Override public boolean isEmpty() { if(size==0) { return true; } return false; } }
2.3 對這個鏈表進行測試(已經過驗證,放心使用)this
public class ListTest01 { public static void main(String[] args) { NewSingleList l1=new NewSingleList(); l1.addItems(4); l1.addItems(7); l1.addItems(66); l1.addItems(233); l1.deleteItems(4); l1.display(); } }
3.1 判斷鏈表是否有環設計
//點擊上述題目連接去LeetCode刷題。第141題 //方法一:雙指針,只要有環,快的指針總會遇上慢的指針,空間複雜度O(1) public class Solution { public boolean hasCycle(ListNode head) { if(head==null || head.next==null){ return false; } ListNode l1=head; ListNode l2=head.next; while(l1 !=null && l2 !=null && l2.next!=null){ if(l1==l2){ return true; } l1=l1.next; l2=l2.next.next; } return false; } } //若是須要讓你用一個指針,檢查一個結點此前是否被訪問過來判斷鏈表是否爲環形鏈表。經常使用的方法是使用哈希表。時間和空間複雜度都是O(n) public class Solution { public boolean hasCycle(ListNode head) { Set<ListNode> l1=new HashSet<>(); while(head != null){ if(l1.contains(head)){ return true; } else{ l1.add(head); } head=head.next; } return false; } }
3.2 找出鏈表交點指針
//鏈表的交點難點在於鏈表的長度不一樣,當同時進行移位的時候,因爲長度不一樣,可能會致使相同的點完美錯過 //例如兩個鏈表,一個是1-2-5-7-8-1,一個是4-3-8-1, //當這兩個同時從頭開始時,若是list1=list1.next;list2=liat2.next;當list2指向8的時候,list1剛指向5,顯然不行。 //可是若是把兩個拼接起來,兩者等長,變成1-2-5-7-8-1-4-3-8-1和 4-3-8-1-1-2-5-7-8-1那就容易多了 // 1-2-5-7-\ /-1-2-5-7-8 // 8-1- // 4-3-/ \4-3-8 public class Solution { public ListNode getIntersectionNode(ListNode headA, ListNode headB) { ListNode l1 = headA, l2 = headB; while (l1 != l2) { l1 = (l1 == null) ? headB : l1.next; l2 = (l2 == null) ? headA : l2.next; } return l1; } }
3.3 鏈表翻轉
class Solution { public ListNode reverseList(ListNode head) { ListNode prev=null; ListNode cur=head; while(cur !=null){ ListNode nextTemp = cur.next; cur.next = prev; prev = cur; cur = nextTemp; } return prev; } }