笔试之链表总结
链表一般也是笔试经常考的一个内容之一,之前参加华为笔试没准备好,上来一个链表把我整蒙了,所以就来总结一下。
首先解题建议和技巧:链表其实有点抽象,尽量多画图,然后利用虚拟头指针,快慢指针,多指针等等;
常见题型:
- 移除链表元素(参考题型leetcode:https://leetcode-cn.com/problems/remove-linked-list-elements/)

这种首先就要利用到虚拟头结点,然后再创建一个尾结点,遍历链表尾结点不断的指向不等于目标值得结点即可,代码如下,需要注意的是尾结点cur指向的结点在变,cur也要移动,因为它是尾结点。
public ListNode removeElements(ListNode head, int val) { ListNode headNode = new ListNode(-1); ListNode cur = headNode; while(head != null){ if(head.val != val){ cur.next = head;//让headnode也有所指 cur = head;// } head = head.next; } cur.next = null; return headNode.next; }

这个题主要就是直接对位相加,注意要满十进位和空节点即可,代码如下:总结一点小知识,求一个数的个位直接对10取余数,求十位则除以10即可得到,另外要注意遍历两个链表的时候,其中一个出现空节点的时候无法取到该结 点的值,所以要先判断。
public ListNode addTwoNumbers(ListNode l1, ListNode l2) { if(l1 == null) return l2; if(l2 == null) return l1; ListNode dummyHead = new ListNode(0); ListNode cur = dummyHead; int res = 0; while(l1 != null || l2 != null){ int v1 = 0; int v2 = 0; if(l1 != null){ v1 = l1.val; } if(l2 != null){ v2 = l2.val; } int sum = l1.val + l2.val + res; res = sum / 10; sum = sum % 10; cur.next = new ListNode(sum ); l1 = l1.next; l2 = l2.next; } if(res > 0) cur.next = new ListNode(res ); return dummyHead.next; }

可以有两种解法,常规的就是先计算两个链表的长度,再根据长度差去让长的链表先走一段。另外一种是一种很巧妙的方法,将短的链表拼接长的链表,长的同样也拼接上短的,比较即可,代码如下,建议使用第二种
1, public ListNode getIntersectionNode(ListNode headA, ListNode headB) { if(headA == null || headB == null) return null; int len1 = 1,len2 = 1; ListNode p = headA; while(p.next != null){ p = p.next; len1++; } ListNode q = headB; while(q.next != null){ q = q.next; len2++; } if(p != q) return null; ListNode t1 = headA; ListNode t2 = headB; if(len1 > len2){ int d = len1-len2; while(d != 0){ t1 = t1.next; d--; } }else{ int d = len2-len1; while(d != 0){ t2 = t2.next; d--; } } while(t1 != t2){ t1 = t1.next; t2 = t2.next; } return t1; } 2,public ListNode getIntersectionNode(ListNode headA, ListNode headB) { if(headA == null || headB == null) return null; ListNode curA = headA; ListNode curB = headB; while(curA != curB){ curA = (curA == null) ?headB:curA.next; curB = (curB== null) ?headA:curB.next; } return curA; }

这个题的解法其实用的还是创建链表的头结点和尾结点,然后尾结点不断的扩展,只不过此题中需要创建两个,一个用来放小于目标值,一个用来放大于等于的,然后再拼接到一起就可以了,注意需要将大于等于的尾结点指向null指针。代码如下:(其实这里可以慢慢形成一个小技巧,每次可以这样来“构造”要返回的链表)
1 public ListNode partition(ListNode head, int x) { 2 ListNode pre = new ListNode(0); 3 ListNode pos = new ListNode(0); 4 ListNode tailA = pre; 5 ListNode tailB = pos; 6 while(head != null){ 7 if(head.val < x){ 8 tailA.next = head; 9 tailA = head; 10 }else { 11 tailB.next = head; 12 tailB = head; 13 } 14 head = head.next; 15 } 16 tailB.next = null; 17 tailA.next = pos.next; 18 return pre.next; 19 }

这个题可以先利用快慢指针找到中间节点,然后把后半部分的链表反转,再与前半部分直接比较即可,代码如下,这个题既可以练习快慢指针也可以练习反转链表,整体还是很好的
1 public boolean isPalindrome(ListNode head) { 2 if(head == null) return true; 3 if(head.next.next == null) return head==head.next; 4 ListNode mid = SearchMid(head);//寻找中间节点 5 ListNode rHead = reverse(mid.next);//反转 6 ListNode lHead = head; 7 while(rHead != null){ 8 if(rHead.val != lHead.val){ 9 return false; 10 } 11 rHead = rHead.next; 12 lHead = lHead.next; 13 } 14 return true; 15 } 16 17 private ListNode reverse(ListNode head) { 18 ListNode pre = null; 19 ListNode cur = head; 20 while(cur != null){ 21 ListNode next = cur.next; 22 cur.next = pre; 23 pre = cur; 24 cur = next; 25 } 26 return pre; 27 } 28 private ListNode SearchMid(ListNode head) { 29 ListNode slow = head; 30 ListNode fast = head; 31 while(fast != null){ 32 fast = fast.next.next; 33 slow = slow.next; 34 } 35 return slow; 36 }

浙公网安备 33010602011771号