19. Remove Nth Node From End of List
题目:移除单链表的倒数第n个节点(仅限一次遍历)
思路:Two Pointer——用两个节点框成长度为n大小的窗,窗移动到链表末尾时,即知道倒数第n个位置。这里要注意头结点的设置,可以有效处理需要移除头结点的情况。
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
public class Solution {
public ListNode removeNthFromEnd(ListNode head, int n) {
if(head == null) return null;
ListNode pre = new ListNode(0);
pre.next = head;
ListNode p = pre;
int count = 0;
while(p.next != null && count < n){
p = p.next;
count++;
}
if(p.next == null) return head.next;
while(p.next != null){
p = p.next;
pre = pre.next;
}
pre.next = pre.next.next;
return head;
}
}
21. Merge Two Sorted Lists
题目:输入两个有序链表,输出合并之后依然有序的链表。
思路:比较大小值,然后往后移,很直接的做法,加了head节点,发现head节点真的很好用。
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
public class Solution {
public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
if(l1 == null) return l2;
if(l2 == null) return l1;
ListNode head = new ListNode(0);
ListNode p = head;
while(l1 != null && l2 != null){
if(l1.val <= l2.val){
p.next = l1;
l1 = l1.next;
}
else{
p.next = l2;
l2 = l2.next;
}
p = p.next;
}
if(l1 != null){
p.next = l1;
}
if(l2 != null){
p.next = l2;
}
return head.next;
}
}
看了其他的解法,都是用递归做的很简单,值得学习。
public ListNode mergeTwoLists(ListNode l1, ListNode l2){
if(l1 == null) return l2;
if(l2 == null) return l1;
if(l1.val < l2.val){
l1.next = mergeTwoLists(l1.next, l2);
return l1;
} else{
l2.next = mergeTwoLists(l1, l2.next);
return l2;
}
}
题目:在一个数组上合并两个数组(长度足够),使其合并后依然有序,
思路:与21题思路完全一致,链表换成数组而已,这里从大数开始比较,很简单。
public class Solution {
public void merge(int[] nums1, int m, int[] nums2, int n) {
int i = m-1, j = n-1, k = m+n-1;
while(i >= 0 && j >= 0){
if(nums1[i] > nums2[j]){
nums1[k--] = nums1[i];
i--;
}
else{
nums1[k--] = nums2[j];
j--;
}
}
while(j >= 0){
nums1[k--] = nums2[j--];
}
}
}
题目:合并k个有序链表,合并之后仍有序。
思路:分治+递归——在21题的基础上加上分治的思想,即将链表数组分割到每两个节点进行比较和拼接。递归是从大往小并,从小往大并的方法比较复杂,不可取。
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
public class Solution {
public ListNode mergeKLists(ListNode[] lists) {
return partion(lists, 0, lists.length-1);
}
public ListNode partion(ListNode[] lists, int left, int right){
if(left == right) return lists[left];
else if(left < right){
int mid = (left+right)/2;
ListNode l1 = partion(lists, left, mid);
ListNode l2 = partion(lists, mid+1, right);
return merge(l1, l2);
}
else{
return null;
}
}
public ListNode merge(ListNode l1, ListNode l2){
if(l1 == null) return l2;
if(l2 == null) return l1;
if(l1.val <= l2.val){
l1.next = merge(l1.next, l2);
return l1;
}
else{
l2.next = merge(l1, l2.next);
return l2;
}
}
}
24. Swap Nodes in Pairs
题目:两两交换节点
思路:设置前节点、p节点和后节点,按顺序进行交换即可,设置一个头结点会更加简单。
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
public class Solution {
public ListNode swapPairs(ListNode head) {
if(head == null || head.next == null) return head;
ListNode pre = new ListNode(0);
pre.next = head;
head = pre;
ListNode p = pre.next;
while(p != null && p.next != null){
ListNode next = p.next.next;
pre.next = p.next;
p.next.next = p;
p.next = next;
pre = p;
p = next;
}
return head.next;
}
}
public class Solution {
public ListNode swapPairs(ListNode head) {
if ((head == null)||(head.next == null))
return head;
ListNode n = head.next;
head.next = swapPairs(head.next.next);
n.next = head;
return n;
}
}
25. Reverse Nodes in k-Group
题目:以k个节点为一组进行反转
思路:递归——先遍历k次,看是否足够k个节点,不足直接返回头结点,足够对该k个节点进行反转,将该k个节点后面的节点递归操作后,设为pre节点。然后对这k个节点进行反转。注意最后返回pre节点。
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
public class Solution {
public ListNode reverseKGroup(ListNode head, int k) {
if(head == null || head.next == null) return head;
ListNode p = head;
for(int i = 0; i< k; i++){
if(p == null) return head;
p = p.next;
}
ListNode pre = reverseKGroup(p, k);
p = head;
for(int i = 0; i < k; i++){
ListNode next = p.next;
p.next = pre;
pre = p;
p = next;
}
return pre;
}
}
61. Rotate List
题目:与旋转数组类似,在倒数第n个位置旋转链表
思路:用了与19题类似的方法,先找到需要旋转的位置,这里n如果大于链表长度,需要取模。
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
public class Solution {
public ListNode rotateRight(ListNode head, int k) {
if(head == null || head.next == null) return head;;
int i = 0;
ListNode p = new ListNode(0);
ListNode q = p;
p.next = head;
while(i < k){
if(p.next == null) {
k = k%i;
p = q;
i = 0;
continue;
}
p = p.next;
i++;
}
if(p.next == null) return head;
while(p.next != null){
p = p.next;
q = q.next;
}
p.next = head;
ListNode temp = q.next;
q.next = null;
return temp;
}
}
其实超长的时候,就已经知道链表长度了,可以算出值来,好像更简单一些。
public ListNode rotateRight(ListNode head, int n) {
if (head==null||head.next==null) return head;
ListNode dummy=new ListNode(0);
dummy.next=head;
ListNode fast=dummy,slow=dummy;
int i;
for (i=0;fast.next!=null;i++)//Get the total length
fast=fast.next;
for (int j=i-n%i;j>0;j--) //Get the i-n%i th node
slow=slow.next;
fast.next=dummy.next; //Do the rotation
dummy.next=slow.next;
slow.next=null;
return dummy.next;
}