206.反转链表
class Solution {
public ListNode reverseList(ListNode head) {
ListNode pre = null;
ListNode cur = head;
ListNode temp = null;
while(cur != null){
temp = cur.next;
cur.next = pre;
pre = cur;
cur = temp;
}
return pre;
}
}
class Solution {
public ListNode reverseList(ListNode head) {
if(head == null || head.next == null){
return head;
}
ListNode p = reverseList(head.next);
head.next.next = head;
head.next = null;
return p;
}
}
92.反转链表II
- 方法1:迭代法,先找到开始需要反转的位置。然后进行依次反转,进行头插。
class Solution {
public ListNode reverseBetween(ListNode head, int m, int n) {
ListNode sentry = new ListNode(0);
sentry.next = head;
int index = n - m;
ListNode pre = sentry;
ListNode tail = head;
while(m > 1){
pre = tail;
tail = tail.next;
m--;
}
while(index > 0){
ListNode next = tail.next;
tail.next = next.next;
next.next = pre.next;
pre.next = next;
index--;
}
return sentry.next;
}
}
class Solution {
ListNode successor = null;
public ListNode reverseBetween(ListNode head, int m, int n) {
if (m == 1) {
return reverseN(head, n);
}
head.next = reverseBetween(head.next, m - 1, n - 1);
return head;
}
public ListNode reverseN(ListNode head, int n) {
if (n == 1) {
successor = head.next;
return head;
}
ListNode last = reverseN(head.next, n - 1);
head.next.next = head;
head.next = successor;
return last;
}
}
83.删除排序链表中的重复元素
class Solution {
public ListNode deleteDuplicates(ListNode head) {
if(head == null){
return head;
}
ListNode pre = head;
while(pre.next != null){
ListNode cur = pre.next;
if(pre.val == cur.val){
pre.next = cur.next;
cur.next = null;
}else{
pre = cur;
cur = cur.next;
}
}
return head;
}
}
86.分隔链表
- 方法1:将链表分割以给定值为界限两个链表,最终拼接链表
class Solution {
public ListNode partition(ListNode head, int x) {
ListNode smallHead = new ListNode(0);
ListNode small = smallHead;
ListNode bigHead = new ListNode(0);
ListNode big = bigHead;
while(head != null){
if(head.val < x){
small.next = head;
small = small.next;
}else{
big.next = head;
big = big.next;
}
head = head.next;
}
big.next = null;
small.next = bigHead.next;
return smallHead.next;
}
}
328.奇偶链表
- 分析:86题类似,可以按照奇偶分为两个链表,最终拼接。
- 代码1:稍显麻烦
class Solution {
public ListNode oddEvenList(ListNode head) {
ListNode smallHead = new ListNode(0);
ListNode small = smallHead;
ListNode bigHead = new ListNode(0);
ListNode big = bigHead;
int index = 1;
while(head != null){
if(index % 2 == 1){
small.next = head;
small = small.next;
}else{
big.next = head;
big = big.next;
}
head = head.next;
index++;
}
big.next = null;
small.next = bigHead.next;
return smallHead.next;
}
}
- 代码2:直接在原始链表中判断奇偶数,主要是奇后必为偶,偶后必为奇。
class Solution {
public ListNode oddEvenList(ListNode head) {
if(head == null){
return head;
}
ListNode odd = head;
ListNode even = head.next;
ListNode evenHead = even;
while(even != null && even.next != null){
odd.next = even.next;
odd = odd.next;
even.next = odd.next;
even = even.next;
}
odd.next = evenHead;
return head;
}
}
2.两数相加
- 分析:将两个链表看成是相同长度的进行遍历,如果一个链表较短则在前面补0,比如987 + 23 = 987 + 023 = 1010。同时,还需要记录每一次的进位与下一次的两数相加,若最终有进位还需进行处理。
- 代码演示:
class Solution {
public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
ListNode pre = new ListNode(0);
ListNode cur = pre;
int carry = 0;
while(l1 != null || l2 != null) {
int x = l1 == null ? 0 : l1.val;
int y = l2 == null ? 0 : l2.val;
int sum = x + y + carry;
carry = sum > 9 ? 1 : 0;
sum = sum % 10;
cur.next = new ListNode(sum);
cur = cur.next;
if(l1 != null)
l1 = l1.next;
if(l2 != null)
l2 = l2.next;
}
if(carry == 1) {
cur.next = new ListNode(carry);
}
return pre.next;
}
}
445.两数相加二
- 分析:可以通过第二题的思路,先将链表反转再就转为第二题,但是如果题目要求不可更改原链表的话,需要借助数据结构:栈。
- 代码1:借助哨兵节点,新节点始终插入到哨兵与链表的头节点之间,最终返回哨兵节点的next,也就是链表的头节点。
class Solution {
public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
int carry = 0;
ListNode pre = new ListNode(0);
pre.next = null;
Stack<Integer> s1 = new Stack<>();
Stack<Integer> s2 = new Stack<>();
while(l1 != null){
s1.push(l1.val);
l1 = l1.next;
}
while(l2 != null){
s2.push(l2.val);
l2 = l2.next;
}
ListNode ans = null;
while(!s1.empty() || !s2.empty()){
int v1 = s1.empty() ? 0 : s1.pop();
int v2 = s2.empty() ? 0 : s2.pop();
int sum = v1 + v2 + carry;
System.out.println(sum);
carry = sum > 9 ? 1 : 0;
sum = sum % 10;
ListNode cur = new ListNode(sum);
cur.next = pre.next;
pre.next = cur;
}
if(carry == 1){
ListNode cur = new ListNode(carry);
cur.next = pre.next;
pre.next = cur;
}
return pre.next;
}
}
- 代码2:在代码1的基础上做一些优化,不需要哨兵节点。新节点直接指向原链表的头节点即可。同时将carry != 0放在while循环中,若最终出现carry == 1的情况还会执行循环体,简化代码。
public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
int carry = 0;
Stack<Integer> s1 = new Stack<>();
Stack<Integer> s2 = new Stack<>();
while(l1 != null){
s1.push(l1.val);
l1 = l1.next;
}
while(l2 != null){
s2.push(l2.val);
l2 = l2.next;
}
ListNode ans = null;
while(!s1.empty() || !s2.empty() || carry != 0){
int v1 = s1.empty() ? 0 : s1.pop();
int v2 = s2.empty() ? 0 : s2.pop();
int sum = v1 + v2 + carry;
System.out.println(sum);
carry = sum > 9 ? 1 : 0;
sum = sum % 10;
ListNode curnode = new ListNode(sum);
curnode.next = ans;
ans = curnode;
}
return ans;
}
203.移除链表元素
class Solution {
public ListNode removeElements(ListNode head, int val) {
if(head == null){
return null;
}
ListNode sentry = new ListNode(0);
sentry.next = head;
ListNode cur = sentry;
while(cur.next != null){
if(cur.next.val == val){
ListNode del = cur.next;
cur.next = del.next;
del.next = null;
}else{
cur = cur.next;
}
}
return sentry.next;
}
}
82.删除链表中的重复元素Ⅱ
class Solution {
public ListNode deleteDuplicates(ListNode head) {
ListNode sentry = new ListNode(0);
sentry.next = head;
if(head == null){
return head;
}
ListNode pre = sentry;
while(pre.next != null && pre.next.next != null){
if(pre.next.val == pre.next.next.val){
ListNode cur = pre.next;
while(cur.next != null && cur.val == cur.next.val){
cur = cur.next;
}
pre.next = cur.next;
}else{
pre = pre.next;
}
}
return sentry.next;
}
}
32.合并两个有序链表
class Solution {
public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
if(l1 == null){
return l2;
}
if(l2 == null){
return l1;
}
ListNode newHead = new ListNode(0);
ListNode pre =newHead;
while(l1 != null && l2 != null){
if(l1.val <= l2.val){
pre.next = l1;
l1 = l1.next;
}else{
pre.next = l2;
l2 = l2.next;
}
pre = pre.next;
}
pre.next = l1 == null ? l2 : l1;
return newHead.next;
}
}
24.两两交换链表中的节点
class Solution {
public ListNode swapPairs(ListNode head) {
if(head == null){
return null;
}
ListNode sentry = new ListNode(0);
sentry.next = head;
ListNode pre = sentry;
while(pre.next != null && pre.next.next != null){
ListNode node1 = pre.next;
ListNode node2 = node1.next;
ListNode next = node2.next;
node2.next = node1;
node1.next = next;
pre.next = node2;
pre = node1;
}
return sentry.next;
}
}
147.对链表进行插入排序
- 方法1:先找到不符合排序顺序的节点,然后从头节点可以,依次比较,找到合适的位置插入
lass Solution {
public ListNode insertionSortList(ListNode head) {
if(head == null){
return head;
}
ListNode sentry = new ListNode(0);
sentry.next = head;
ListNode cur = head.next;
ListNode pre = head;
while(cur != null){
if(pre.val < cur.val){
pre = cur;
cur = cur.next;
}
else{
ListNode p = sentry;
while(p.next.val < cur.val){
p = p.next;
}
pre.next = cur.next;
cur.next = p.next;
p.next = cur;
cur = pre.next;
}
}
return sentry.next;
}
}
148.排序链表
class Solution {
public ListNode sortList(ListNode head) {
if(head == null || head.next == null){
return head;
}
ListNode mid = middleNode(head);
ListNode rightHead = mid.next;
mid.next = null;
ListNode left = sortList(head);
ListNode right = sortList(rightHead);
return merge(left,right);
}
public ListNode middleNode(ListNode head) {
if(head == null || head.next == null){
return head;
}
ListNode slow = head, fast = head.next.next;
while (fast != null && fast.next != null) {
slow = slow.next;
fast = fast.next.next;
}
return slow;
}
public ListNode merge(ListNode l1, ListNode l2){
ListNode sentry = new ListNode(-1);
ListNode curr = sentry;
while(l1 != null && l2 != null) {
if(l1.val < l2.val) {
curr.next = l1;
l1 = l1.next;
} else {
curr.next = l2;
l2 = l2.next;
}
curr = curr.next;
}
curr.next = l1 != null ? l1 : l2;
return sentry.next;
}
}
19.删除链表中的倒数第N个节点
- 方法1(麻烦):总体思路为先确定链表的长度,然后根据索引找到倒数第n个元素,删除即可
class Solution {
public ListNode removeNthFromEnd(ListNode head, int n) {
if(head == null){
return head;
}
ListNode sentry = new ListNode(0);
sentry.next = head;
ListNode cur = head;
ListNode pre = sentry;
int index = 0;
int len = 0;
while(cur != null ){
cur = cur.next;
len++;
}
cur = head;
while(cur != null){
if(len - index != n){
pre = cur;
cur = cur.next;
index++;
}else{
pre.next = cur.next;
break;
}
}
return sentry.next;
}
}
- 方法2:利用双指针,pre指针与last指针之间的索引相差n+1,当last指针指向null时,pre指针指向删除节点的前一个节点,即可进行删除。
class Solution {
public ListNode removeNthFromEnd(ListNode head, int n) {
ListNode sentry = new ListNode(0);
sentry.next = head;
int index = 0;
ListNode pre = sentry;
ListNode last = sentry;
while(last != null){
if(index <= n){
index++;
}else{
pre = pre.next;
}
last = last.next;
}
pre.next = pre.next.next;
return sentry.next;
}
class Solution {
public ListNode removeNthFromEnd(ListNode head, int n) {
ListNode sentry = new ListNode(0);
sentry.next = head;
ListNode pre = sentry;
ListNode last = sentry;
for(int i = 0; i < n+1;i++){
last = last.next;
}
while(last != null){
last = last.next;
pre = pre.next;
}
pre.next = pre.next.next;
return sentry.next;
}
}
61.旋转链表
- 方法1:先找到倒数第k个节点,方式如同题19,利用双指针找到第k-1个节点,然后依次头插第K个节点。
class Solution {
public ListNode rotateRight(ListNode head, int k) {
if(head == null || head.next == null){
return head;
}
ListNode sentry = new ListNode(0);
sentry.next = head;
ListNode cur = head;
int len = 0;
while(cur != null){
cur = cur.next;
len++;
}
int index = k % len;
ListNode pre = sentry;
ListNode last = sentry;
for(int i = 0 ; i < index + 1;i++){
last = last.next;
}
while(last != null){
pre = pre.next;
last = last.next;
}
ListNode p = sentry;
while(pre.next != null){
cur = pre.next;
pre.next = cur.next;
cur.next = p.next;
p.next = cur;
p = p.next;
}
return sentry.next;
}
public ListNode rotateRight(ListNode head, int k) {
if(head == null){
return head;
}
ListNode sentry = new ListNode(0);
sentry.next = head;
ListNode cur = head;
int len = 1;
while(cur.next != null){
cur = cur.next;
len++;
}
cur.next = head;
int index = len - k % len;
ListNode last = sentry;
for(int i = 0 ; i < index;i++){
last = last.next;
}
ListNode temp = last.next;
sentry.next = temp;
last.next = null;
return sentry.next;
}
}
- 方法2:将链表串环,然后在合适的位置断开链表,则旋转成功。
class Solution {
public ListNode rotateRight(ListNode head, int k) {
if(head == null){
return head;
}
ListNode sentry = new ListNode(0);
sentry.next = head;
ListNode cur = head;
int len = 1;
while(cur.next != null){
cur = cur.next;
len++;
}
cur.next = head;
int index = len - k % len;
ListNode last = sentry;
for(int i = 0 ; i < index;i++){
last = last.next;
}
ListNode temp = last.next;
sentry.next = temp;
last.next = null;
return sentry.next;
}
}
143.重排链表
- 方法1:确定链表长度,确定循环次数。循环体内部逻辑为,每次找到最后一个节点,然后通过头插法插到合适的位置。
class Solution {
public void reorderList(ListNode head) {
if(head !=null){
ListNode last = head;
ListNode pre = head;
int len = 1;
while(last.next != null){
last = last.next;
len++;
}
int index = 1;
int sum = (len - 1) / 2;
while(sum-- > 0){
last = pre;
while(last.next.next != null){
last = last.next;
}
ListNode temp = last.next;
temp.next = pre.next;
pre.next = temp;
last.next = null;
pre = temp.next;
}
}
}
}
- 方法2:如方法1所示,链表每次需要遍历才能找到末尾节点。因此可以借助数组与双指针完成操作。
class Solution {
public void reorderList(ListNode head) {
if(head == null){
return;
}
ArrayList<ListNode> list = new ArrayList<>();
ListNode cur = head;
while(cur != null){
list.add(cur);
cur = cur.next;
}
int left = 0;
int right = list.size() - 1;
while(left < right){
list.get(left).next = list.get(right);
left++;
if(left == right){
break;
}
list.get(right).next = list.get(left);
right--;
}
list.get(left).next = null;
}
}
234.回文链表
- 方法1:与143题方法2类似,通过数组以及双指针依次比较对应的索引的ListNode.val是否相等。
class Solution {
public boolean isPalindrome(ListNode head) {
if(head == null || head.next == null){
return true;
}
ArrayList<Integer> list = new ArrayList<>();
ListNode cur = head;
while(cur != null){
list.add(cur.val);
cur = cur.next;
}
int left = 0;
int right = list.size() - 1;
while(left < right){
if(!list.get(left).equals(list.get(right)) ){
return false;
}
left++;
right--;
}
return true;
}
}
- 方法2:找到中间节点,然后反转后半部分链表。此刻,即原始链表变为两个链表,依次比较链表的值,确定是否回文。
class Solution {
public boolean isPalindrome(ListNode head) {
ListNode fast = head, slow = head;
while (fast != null && fast.next != null) {
fast = fast.next.next;
slow = slow.next;
}
if (fast != null) {
slow = slow.next;
}
slow = reverse(slow);
fast = head;
while (slow != null) {
if (fast.val != slow.val)
return false;
fast = fast.next;
slow = slow.next;
}
return true;
}
public ListNode reverse(ListNode head) {
ListNode prev = null;
while (head != null) {
ListNode next = head.next;
head.next = prev;
prev = head;
head = next;
}
return prev;
}
}