目录
9.convert-sorted-list-to-binary-search-tree
10.remove-nth-node-from-end-of-list
1.linked-list-cycle
题目:判断给定的链表中是否有环,满足不使用额外的空间
分析:利用快慢指针,如果快慢指针能相遇则说明有环
public boolean hasCycle(ListNode head) {
ListNode low = head;
ListNode quick = head;
while(quick != null && quick.next != null){
quick = quick.next.next;
low = low.next;
if(low == quick)
return true;
}
return false;
}
2.linked-list-cycle-ii
题目:对于一个给定的链表,返回环的入口节点,如果没有环,返回null
分析:见剑指offer面试题23 https://blog.csdn.net/Nibaby9/article/details/104050540
3.partition-list
题目:给出一个链表和一个值x,以x为参照将链表划分成两部分,使所有小于x的节点都位于大于或等于x的节点之前。两个部分之内的节点之间要保持的原始相对顺序。例如:给出1->4->3->2->5->2和x = 3,返回1->2->2->4->3->5.
分析:新建立两个结点,将小于x的结点与大于等于x的结点分别插到这两个结点之后,形成两条链表,最后将两条链表连起来即可。
public ListNode partition(ListNode head, int x) {
ListNode head1 = new ListNode(0);
ListNode head2 = new ListNode(0);
ListNode cur = head,cur1 = head1,cur2 = head2;
while(cur != null){
if(cur.val < x){
cur1.next = cur;
cur1 = cur1.next;
}
else{
cur2.next = cur;
cur2 = cur2.next;
}
cur = cur.next;
}
cur1.next = head2.next;
cur2.next = null;
return head1.next;
}
4.reverse-linked-list-ii
题目:将一个链表m位置到n位置之间的区间反转,要求使用原地算法,并且在一次扫描之内完成反转。例如:给出的链表为1->2->3->4->5->NULL, m = 2 ,n = 4,返回1->4->3->2->5->NULL。注意:给出的m,n满足以下条件:1 ≤ m ≤ n ≤ 链表长度
分析:定义两个指针,指针pre指向链表开始反转的前一个位置,指针start指向链表反转的第一个位置。每次删除start的后一个节点,再该结点插入pre后面,需删除n-m次即可。注意:链表的头结点可能会发生变化,需要创建一个新节点来指向链表的头结点。
翻转链表类似题见剑指offer面试题24 https://blog.csdn.net/Nibaby9/article/details/104050540
public ListNode reverseBetween(ListNode head, int m, int n){
ListNode preHead = new ListNode(0);//方便返回链表头结点,修改后的头结点有可能不是head
preHead.next = head;//勿漏
ListNode pre = preHead;
ListNode start = head;
for(int i = 1;i < m;i++){
pre = start;
start = start.next;
}
for(int i = 1;i <= n - m;i++) {//需要删n-m次
ListNode temp = start.next;
start.next = temp.next;
temp.next = pre.next;
pre.next = temp;
}
return preHead.next;
}
5.reverse-nodes-in-k-group
题目:将给出的链表中的节点每k个一组翻转,返回翻转后的链表。如果链表中的节点数不是k的倍数,将最后剩下的节点保持原样。你不能更改节点中的值,只能更改节点本身。只允许使用常数级的空间。例如:给定的链表是1->2->3->4->5,对于 k = 2, 你应该返回 2->1->4->3->5;对于 k = 3, y你应该返回 3->2->1->4->5
分析:递归。将前k个节点与剩下节点断开,翻转前k个节点,递归求解剩下节点,再将两条链表合并即可。
public ListNode reverseKGroup(ListNode head, int k) {
ListNode end = head;
int index = 1;
while(index < k && end != null){
end = end.next;
index++;
}
if(end == null || index < k)
return head;
ListNode head2 = end.next;
end.next = null;
head2 = reverseKGroup(head2,k);
ListNode head1 = reverse(head);
head.next = head2;
return head1;
}
private ListNode reverse(ListNode head) {
ListNode cur = head,pre = null;
while(cur != null){
ListNode temp = cur.next;
cur.next = pre;
pre = cur;
cur = temp;
}
return pre;
}
6.rotate-list
题目:将给定的链表向右转动k个位置,k是非负数。例如:给定1->2->3->4->5->null , k=2,返回4->5->1->2->3->null。
分析:特别注意k可能大于链表长度!!!因此k = k%len。将尾结点next指针指向首节点,形成一个环,接着往后跑len-k步,就是所需链表的尾结点,从这断开链表即可。
public ListNode rotateRight(ListNode head, int n) {
if (head == null || head.next == null || n == 0)
return head;
int len = 1;
ListNode tail = head;
while(tail.next != null){
len++;
tail = tail.next;
}
tail.next = head;//首尾相连形成环
for(int i = 0;i < len - n % len;i++){//注意n有可能大于链表长度
tail = tail.next;
}
head = tail.next;
tail.next = null;
return head;
}
7.reorder-list
题目:将给定的单链表L: L 0→L 1→…→L n-1→L n,重新排序为: L 0→L n →L 1→L n-1→L 2→L n-2→…要求使用原地算法,并且不改变节点的值。例如:对于给定的单链表{1,2,3,4},将其重新排序为{1,4,2,3}.
分析:将链表分成两半,然后将后半部分翻转,最后拼接两个链表即可。
public void reorderList(ListNode head) {
if(head == null)
return;
//将链表从中间断开
ListNode mid = findMid(head);
ListNode head2 = mid.next;
mid.next = null;
//将链表的前半部分和反转后的后半部分合并
ListNode cur1 = head,cur2 = reverse(head2);
while(cur1 != null && cur2 != null){
ListNode temp1 = cur1.next;
ListNode temp2 = cur2.next;
cur1.next = cur2;
cur2.next = temp1;
cur1 = temp1;
cur2 = temp2;
}
}
private ListNode reverse(ListNode head) {
ListNode pre = null,cur = head;
while(cur != null){
ListNode temp = cur.next;
cur.next = pre;
pre = cur;
cur = temp;
}
return pre;
}
private ListNode findMid(ListNode head) {
ListNode low = head,fast = head;
while(fast != null && fast.next != null){
low = low.next;
fast = fast.next.next;
}
return low;
}
8.swap-nodes-in-pairs
题目:将给定的链表中每两个相邻的节点交换一次,返回链表的头指针。例如,给出1->2->3->4,你应该返回链表2->1->4->3。你给出的算法只能使用常量级的空间。你不能修改列表中的值,只能修改节点本身。
分析:递归求解即可。
public ListNode swapPairs(ListNode head) {
if(head == null || head.next == null)
return head;
ListNode temp = head.next;
head.next = swapPairs(temp.next);
temp.next = head;
return temp;
}
9.convert-sorted-list-to-binary-search-tree
题目:给定一个单链表,其中的元素按升序排序,请将它转化成平衡二叉搜索树(BST)
分析:先利用快慢指针找到单链表的中间节点,然后以该节点为根结点,再把原链表断开,分为前后两个链表,递归调用原函数,分别为根结点的左右子树。注意参数的设计,传递的是链表的第一个结点和最后一个节点的next。
public TreeNode sortedListToBST(ListNode head) {
return toBST(head,null);
}
private TreeNode toBST(ListNode head, ListNode tail) {
if(head == tail)
return null;
ListNode quick = head;
ListNode low = head;
while(quick != tail && quick.next != tail){
low = low.next;
quick = quick.next.next;
}
TreeNode root = new TreeNode(low.val);
root.left = toBST(head,low);
root.right = toBST(low.next,tail);
return root;
}
10.remove-nth-node-from-end-of-list
题目:给定一个链表,删除链表的倒数第n个节点并返回链表的头指针。例如, 给出的链表为:1->2->3->4->5, n= 2.↵↵ 删除了链表的倒数第n个节点之后,链表变为1->2->3->5.备注:题目保证n一定是合法的;请尝试只用一步操作完成该功能
分析:删除倒数第n个节点需先找出倒数第n+1个节点。倒数数第n+1个节点也就是第len-n个节点,采用快慢指针,快指针先走出n步,随后两个指针同时前进,当快指针到达链表尾部时,慢指针刚好到达倒数第n+1个节点的位置。注意删除节点为链表头结点的情况。类似题见剑指offer面试题22 https://blog.csdn.net/Nibaby9/article/details/104050540
public ListNode removeNthFromEnd(ListNode head, int n) {
ListNode preHead = new ListNode(0);
preHead.next = head;
ListNode quick = preHead;
ListNode slow = preHead;
for(int i = 0;i < n;i++)
quick = quick.next;
while(quick.next != null){
slow = slow.next;
quick = quick.next;
}
slow.next = slow.next.next;
return preHead.next;
}