标签(空格分隔):笔记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; } }