链表
1环形链表插值
有一个整数val,如何在节点值有序的环形链表中插入一个节点值为val的节点,并且保证这个环形单链表依然有序。
给定链表的信息,及元素的值A及对应的nxt指向的元素编号同时给定val,请构造出这个环形链表,并插入该值。
[1,3,4,5,7],[1,2,3,4,0],2
返回:{1,2,3,4,5,7}
思路:判断链表是否为空,为空,直接返回head即可
不为空,如果head.val>=val,将只插到head之前
设置preNode,nextNode,若curNode在preNode和nextNode之间,插入
import java.util.*; /* public class ListNode { int val; ListNode next = null; ListNode(int val) { this.val = val; } }*/ public class InsertValue { public ListNode insert(int[] A, int[] nxt, int val) { // write code here if(A.length == 0){ ListNode curNode = new ListNode(val); //curNode.next= curNode; return curNode; } //构造环形链表 int len = A.length; ListNode head= new ListNode(A[0]); ListNode tail = head; for(int i=0;i<len-1;i++){ ListNode curNode = new ListNode(A[nxt[i]]); tail.next = curNode; tail = curNode; } //tail.next = head; //插入值 ListNode preNode = head; ListNode nextNode = preNode.next; if(head.val>=val){ ListNode curNode = new ListNode(val); curNode.next = head; //tail.next = curNode; return curNode; } while(nextNode!=null&&val>nextNode.val){ preNode = nextNode; nextNode = preNode.next; } ListNode curNode = new ListNode(val); curNode.next = nextNode; preNode.next = curNode; return head; } }
2访问单个节点的删除
实现一个算法,删除单向链表中间的某个结点,假定你只能访问该结点。
给定带删除的节点,请执行删除操作,若该节点为尾节点,返回false,否则返回true
思路:判断该节点的next节点,如果为空,返回false,如果不为空,将next节点值复制给该节点,且将该节点的next赋值为next的next
import java.util.*; /* public class ListNode { int val; ListNode next = null; ListNode(int val) { this.val = val; } }*/ public class Remove { public boolean removeNode(ListNode pNode) { // 特殊情况,如果是尾结点,删除操作不成功! if(pNode.next == null) { return false; } pNode.val = pNode.next.val; // 可以不用临时变量 pNode.next = pNode.next.next; // 注意返回值必须写 return true; } }
3链表的分化
对于一个链表,我们需要用一个特定阈值完成对它的分化,使得小于等于这个值的结点移到前面,大于该值的结点在后面,同时保证两类结点内部的位置关系不变。
给定一个链表的头结点head,同时给定阈值val,请返回一个链表,使小于等于它的结点在前,大于等于它的在后,保证结点值不重复。
{1,4,2,5},3
{1,2,4,5}
思路:将链表分为2个,smallerList和biggerList,如果值<=val,放到小链表,反之放到大链表,最后整体串联起来
import java.util.*; /* public class ListNode { int val; ListNode next = null; ListNode(int val) { this.val = val; } }*/ public class Divide { public ListNode listDivide(ListNode head, int val) { if(head == null || head.next == null) return head; ListNode node = head, smallerList = null, biggerList = null; ListNode tmp = null, smallerListTail = null, biggerListTail = null; while (node != null) { tmp = node; node = node.next; tmp.next = null; int value = tmp.val; if(value <= val) { if(smallerList == null) smallerList = tmp; else smallerListTail.next = tmp; smallerListTail = tmp; } else { if(biggerList == null) biggerList = tmp; else biggerListTail.next = tmp; biggerListTail = tmp; } } if(smallerListTail == null) return biggerList; else if(biggerList == null) return smallerList; smallerListTail.next = biggerList; return smallerList; } }
4打印两个链表的公共值
现有两个升序链表,且链表中均无重复元素。请设计一个高效的算法,打印两个链表的公共值部分。
给定两个链表的头指针headA和headB,请返回一个vector,元素为两个链表的公共部分。请保证返回数组的升序。两个链表的元素个数均小于等于500。保证一定有公共值
{1,2,3,4,5,6,7},{2,4,6,8,10}
返回:[2.4.6]
思路:如果两个链表有任何一个为空,则返回null
反之,依次比较两个节点值,不等移动,相等记录到ArrayList集合中,那个小向下一个节点移动
import java.util.*; /* public class ListNode { int val; ListNode next = null; ListNode(int val) { this.val = val; } }*/ public class Common { public int[] findCommonParts(ListNode headA, ListNode headB) { // write code here if(headA == null || headB == null) return null; List<Integer> list = new ArrayList<Integer>(); while(headA != null && headB != null) { if(headA.val < headB.val) headA = headA.next; else if(headA.val > headB.val) headB = headB.next; else if(headA.val == headB.val) { list.add(headA.val); headA = headA.next; headB = headB.next; } } int[] res = new int[list.size()]; for(int i = 0; i < list.size(); i++) { res[i] = list.get(i); } return res; } }
5链表的k逆序
有一个单链表,请设计一个算法,使得每K个节点之间逆序,如果最后不够K个节点一组,则不调整最后几个节点。例如链表1->2->3->4->5->6->7->8->null,K=3这个例子。调整后为,3->2->1->6->5->4->7->8->null。因为K==3,所以每三个节点之间逆序,但其中的7,8不调整,因为只有两个节点不够一组。
给定一个单链表的头指针head,同时给定K值,返回逆序后的链表的头指针。
import java.util.*; /* public class ListNode { int val; ListNode next = null; ListNode(int val) { this.val = val; } }*/ public class KInverse { public ListNode inverse(ListNode head, int k) { ListNode cur = head; int count = 0; while(cur!=null && count!=k) { cur = cur.next; count++; } //此时cur为第k+1个节点 if(count==k) { cur = inverse(cur,k); while(count-- >0) { ListNode tmp = head.next; head.next = cur; cur = head; head = tmp; } //cur为翻转后的第一个节点 head = cur; } return head; } }
栈实现
import java.util.*; /* public class ListNode { int val; ListNode next = null; ListNode(int val) { this.val = val; } }*/ public class KInverse { public ListNode inverse(ListNode head, int k) { // write code here Stack<Integer> stack = new Stack<Integer>(); stack.push(head.val); int count = 1; ListNode curHead = head; ListNode temp = head; while(temp.next != null) { temp = temp.next; stack.push(temp.val); count++; if(count == k) { while(!stack.isEmpty()) { curHead.val = stack.pop(); curHead = curHead.next; } count = 0; } } return head; } }
6链表指定值清除
现在有一个单链表。链表中每个节点保存一个整数,再给定一个值val,把所有等于val的节点删掉。
给定一个单链表的头结点head,同时给定一个值val,请返回清除后的链表的头结点,保证链表中有不等于该值的其它值。请保证其他元素的相对顺序。
{1,2,3,4,3,2,1},2
{1,3,4,3,1}
思路:判断这个节点,为头节点
非头非尾节点
尾节点
import java.util.*; /* public class ListNode { int val; ListNode next = null; ListNode(int val) { this.val = val; } }*/ public class ClearValue { public ListNode clear(ListNode head, int val) { // write code here ListNode cur = head; ListNode pre = cur; while(head != null && head.val == val) { head = head.next; cur = head; pre = cur; } //删除元素非头节点 while(cur.next != null) { cur = cur.next; if(cur.val == val) { if(cur.next == null) { pre.next = null; } else { pre.next = cur.next; cur = pre; } } pre = cur; } return head; } }
7链表的回文结构
请编写一个函数,检查链表是否为回文。
给定一个链表ListNode* pHead,请返回一个bool,代表链表是否为回文。
{1,2,3,2,1}
返回:true
{1,2,3,2,3}
返回:false
import java.util.*; /* public class ListNode { int val; ListNode next = null; ListNode(int val) { this.val = val; } }*/ public class Palindrome { public boolean isPalindrome(ListNode pHead) { if(pHead == null) return true; ListNode slow = pHead; ListNode fast = pHead; while(fast.next!=null && fast.next.next!=null) { slow = slow.next; fast = fast.next.next; } //如果是奇数节点,此时slow为中间那个节点;如果是偶数节点,此时slow为前半段最后一个节点 ListNode rhead = slow.next; slow.next = null; //对rhead开始的链表进行翻转 ListNode pre = null; while(rhead!=null) { ListNode tmp = rhead.next; rhead.next = pre; pre = rhead; rhead = tmp; } //此时pre为翻转后的头节点 while(pre!=null && pHead!=null) { if(pre.val != pHead.val) { return false; } pre = pre.next; pHead = pHead.next; } return true; } }
用了栈
import java.util.*; /* public class ListNode { int val; ListNode next = null; ListNode(int val) { this.val = val; } }*/ public class Palindrome { public boolean isPalindrome(ListNode pHead) { // write code here Stack<Integer> s = new Stack<Integer>(); ListNode mynode = pHead; while(mynode != null){ s.push(mynode.val); mynode = mynode.next; } int i = (int)s.size()/2; mynode = pHead; for(; i > 0; i--){ if(mynode.val != s.pop()){ return false; } mynode = mynode.next; } return true; } }
8复杂链表的复制
输入一个复杂链表(每个节点中有节点值,以及两个指针,一个指向下一个节点,另一个特殊指针指向任意一个节点)。
思路:链表元素复制
为复制后的元素加上Rand指针
分开原来的指针和复制后的指针
/* public class RandomListNode { int label; RandomListNode next = null; RandomListNode random = null; RandomListNode(int label) { this.label = label; } } */ public class Solution { public RandomListNode Clone(RandomListNode pHead) { if(pHead==null) return pHead; RandomListNode node = pHead; RandomListNode tmp = null; while(node!=null){ //拷贝 tmp = node.next; node.next = new RandomListNode(node.label); node.next.next = tmp; node = tmp; } node = pHead; RandomListNode nodeCopy = null; while(node!=null){//拷贝节点random指针 tmp = node.next.next; nodeCopy = node.next; nodeCopy.random = (node.random==null)?null: node.random.next; node = tmp; } node = pHead; RandomListNode resHead = pHead.next; while(node!=null){//分离出两个链表 tmp = node.next.next; nodeCopy = node.next; node.next = tmp; nodeCopy.next = (tmp==null)?null:tmp.next; node = tmp; } return resHead; } }
/* public class RandomListNode { int label; RandomListNode next = null; RandomListNode random = null; RandomListNode(int label) { this.label = label; } } */ public class Solution { public RandomListNode Clone(RandomListNode pHead) { if(pHead==null) return null; RandomListNode cur = pHead; //在原有链表后面复制节点 while(cur!=null) { RandomListNode tmp = new RandomListNode(cur.label); tmp.next = cur.next; cur.next = tmp; cur = tmp.next; } //完成随机指针 cur = pHead; while(cur!=null) { if(cur.random!=null) { cur.next.random = cur.random; } cur = cur.next.next; } RandomListNode nhead = pHead.next; cur = pHead; //第三次遍历 将链表分离 while(cur!=null) { RandomListNode tmp = cur.next; cur.next = tmp.next; if(tmp.next!=null) { tmp.next = tmp.next.next; } cur = cur.next; } return nhead; } }
9链表判环
如何判断一个单链表是否有环?有环的话返回进入环的第一个节点的值,无环的话返回-1。如果链表的长度为N,请做到时间复杂度O(N),额外空间复杂度O(1)。
给定一个单链表的头结点head(注意另一个参数adjust为加密后的数据调整参数,方便数据设置,与本题求解无关),请返回所求值。
思路:快慢指针,快指针,一次走2步,慢指针一次走1步,慢指针为空,无环,返回null
有环,快慢指针相遇,快指针从链表头节点,一次走1步,慢指针继续走,快慢指针再次相遇,次节点为第一个入环节点
import java.util.*; /* public class ListNode { int val; ListNode next = null; ListNode(int val) { this.val = val; } }*/ public class ChkLoop { public int chkLoop(ListNode head, int adjust) { // write code here if(head==null) return -1; ListNode slow=head; ListNode fast=head; while(fast!=null&& fast.next!=null){ slow=slow.next; fast=fast.next.next; if(slow==fast){ break; } } if(fast==null||fast.next==null){ return -1; } fast=head; while(slow!=fast){ slow=slow.next; fast=fast.next; } return slow.val; } }
10无环单链表判相交
现在有两个无环单链表,若两个链表的长度分别为m和n,请设计一个时间复杂度为O(n + m),额外空间复杂度为O(1)的算法,判断这两个链表是否相交。
给定两个链表的头结点headA和headB,请返回一个bool值,代表这两个链表是否相交。保证两个链表长度小于等于500。
import java.util.*; /* public class ListNode { int val; ListNode next = null; ListNode(int val) { this.val = val; } }*/ public class CheckIntersect { public boolean chkIntersect(ListNode headA, ListNode headB) { // write code here if (headA == null || headB == null) return false; int n = 0; ListNode cur1 = headA; while (cur1.next != null) { n++; cur1 = cur1.next; } ListNode cur2 = headB; while (cur2.next != null) { n--; cur2 = cur2.next; } return cur1 == cur2; } }
11有环单链表判相交
如何判断两个有环单链表是否相交?相交的话返回第一个相交的节点,不想交的话返回空。如果两个链表长度分别为N和M,请做到时间复杂度O(N+M),额外空间复杂度O(1)。
给定两个链表的头结点head1和head2(注意,另外两个参数adjust0和adjust1用于调整数据,与本题求解无关)。请返回一个bool值代表它们是否相交。
import java.util.*; /* public class ListNode { int val; ListNode next = null; ListNode(int val) { this.val = val; } }*/ public class ChkIntersection { public boolean chkInter(ListNode head1, ListNode head2, int adjust0, int adjust1) { // write code here ListNode loopNode1 = chkLoop(head1); ListNode loopNode2 = chkLoop(head2); //入环节点相同,(找入环节点之前相交的节点) if(loopNode1 == loopNode2) return true; else { ListNode cur = loopNode1.next ; while(cur != loopNode1) { if(cur == loopNode2) return true; cur = cur.next; } return false; } } //判断链表是否有环,返回有环链表的入环第一个节点 public ListNode chkLoop(ListNode head) { // write code here if(head == null || head.next == null) return null; ListNode slow = head; ListNode quick = head; //注意判断结束条件 while(quick != null&& quick.next != null) { slow = slow.next; quick = quick.next.next; if(quick == slow) break; } if(quick != slow) return null; //有环,寻找入环的第一个节点值 quick = head; while(quick != slow) { quick = quick.next; slow = slow.next; } return quick; } }
12单链表相交判断
给定两个单链表的头节点head1和head2,如何判断两个链表是否相交?相交的话返回true,不想交的话返回false。
给定两个链表的头结点head1和head2(注意,另外两个参数adjust0和adjust1用于调整数据,与本题求解无关)。请返回一个bool值代表它们是否相交。
import java.util.*; /* public class ListNode { int val; ListNode next = null; ListNode(int val) { this.val = val; } }*/ public class ChkIntersection { public boolean chkInter(ListNode head1, ListNode head2, int adjust0, int adjust1) { ListNode e1 = cycleNode(head1); ListNode e2 = cycleNode(head2); if((e1 != null && e2 == null) || (e1 == null && e2 != null)) return false; if(e1 != null && e1 == e2) return true; ListNode t = e1.next; while(t != e1){ if(t == e2) return true; t = t.next; } return false; } //获取入环节点 private ListNode cycleNode(ListNode head){ ListNode f = head,s = head; if(f.next != null){ f = f.next.next; s = s.next; }else{ return null; } while(f != null && f != s){ f = f.next; s = s.next; if(f != null){ f = f.next; }else{ return null; } } f = head; while(f != s){ f = f.next; s = s.next; } return f; } }

浙公网安备 33010602011771号