一 反转链表
1.1题目
给定一个单链表的头结点pHead(该头节点是有值的,比如在下图,它的val是1),长度为n,反转该链表后,返回新链表的表头。
数据范围: 0≤n≤1000
要求:空间复杂度 O(1) ,时间复杂度 O(n) 。
如当输入链表{1,2,3}时,
经反转后,原链表变为{3,2,1},所以对应的输出为{3,2,1}。
1->2->3变成3->2->1
原题目:反转链表_牛客题霸_牛客网
1.2解决思路及代码
/*
public class ListNode
{
public int val;
public ListNode next;
public ListNode (int x)
{
val = x;
}
}*/
class Solution
{
public ListNode ReverseList(ListNode pHead)
{
//判断如果链表为空或者只有一个元素时,返回本身
if(pHead==null||pHead.next==null){
return pHead;
}
//current放到第二个位置,作为会插入到首节点之前的节点
ListNode current=pHead.next;
//首节点的next的值设为空,因为首节点在反转后会是最后一个节点,最后一个节点的next为空
pHead.next=null;
//遍历除了首节点之外的所有节点
while(current!=null){
//next作为下一次插入的current值,主要作用是记住遍历元素的后一个位置
ListNode next=current.next;
//当前遍历元素,放在首节点的前面
current.next=pHead;
//首节点发生改变,首节点为刚刚插到最开始位置的节点
pHead=current;
//到一下个遍历的节点,及上次的next
current=next;
}
return pHead;
}
}
二 链表内指定区间反转
2.1题目
将一个节点数为 size 链表 m 位置到 n 位置之间的区间反转,要求时间复杂度 O(n),空间复杂度 O(1)。
例如:
给出的链表为 1→2→3→4→5→NULL, m=2,n=4
返回 1→4→3→2→5→NULL
2.2思路以及代码
如果m=2,n=4
dummy(-1) -> | 1-> | 2-> | 3-> | 4-> | 5-> | null |
count=0 | 1 | 2 | 3 | 4 | 5 | |
pre(指向翻转链表的首节点) count=1 | last(指向不翻转列表后端的首元素) current | next |
一下是c#的代码
using System;
using System.Collections.Generic;
/*
public class ListNode
{
public int val;
public ListNode next;
public ListNode (int x)
{
val = x;
}
}
*/
class Solution {
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param head ListNode类
* @param m int整型
* @param n int整型
* @return ListNode类
*/
public ListNode reverseBetween (ListNode head, int m, int n) {
// write code here
if(head==null||head.next==null||m==n){
return head;
}
ListNode dummyNode=new ListNode(-1);
dummyNode.next=head;
int count=0;
ListNode current=dummyNode;
while(current.next!=null&&count<m-1){
current=current.next;
count++;
}
ListNode pre=current;
current=current.next;
ListNode last=current;
ListNode phead=current;
current=current.next;
count+=2;
while(current!=null&&count<=n){
ListNode next=current.next;
current.next=phead;
last.next=next;
pre.next=current;
phead=current;
current=next;
count++;
}
return dummyNode.next;
}
}
2.3java的代码
这种办法更简洁,需要自己去画一遍过程
import java.util.*;
/*
* public class ListNode {
* int val;
* ListNode next = null;
* }
*/
public class Solution {
/**
*
* @param head ListNode类
* @param m int整型
* @param n int整型
* @return ListNode类
*/
public ListNode reverseBetween (ListNode head, int m, int n) {
ListNode dummyNode=new ListNode(-1);//创建头结点
dummyNode.next=head;
ListNode pre=dummyNode;//pre代表翻转段,前面的元素
for(int i=0;i<m-1;i++){//确定翻转段前最后一个不动的位置是那个节点
pre=pre.next;
}
ListNode cur=pre.next;
ListNode next;
for(int k=0;k<n-m;k++){//这个比上面的简洁精妙,cur永远都是最开始翻转区间的第一个元素,翻转后,是区间的最后一个元素
next=cur.next;//next表示要放在翻转区间最前面的首元素
cur.next=next.next;//cur.next永远指向下一个翻转的元素,或者指向不翻转的后端第一个
next.next=pre.next;//当前元素指向首位置
pre.next=next;//翻转前的末尾指向此时翻转链表的首元素
}
return dummyNode.next;
}
}
(1)1->2->3->4->5->null
(2)-1->1->2->3->4->5->null
确定pre指向1,cur指向2,next指向3 next=cur.next;
-1->1->2->4->5->null 3->4 cur.next=next.next;
-1->1->2->4->5->null 3->2 next.next=pre.next;
-1->1->3->2->4->5->null pre.next=next;
(3)按照这个步骤下去
三 链表中的节点每k个一组翻转
3.1题目
将给出的链表中的节点每 k 个一组翻转,返回翻转后的链表
如果链表中的节点数不是 k 的倍数,将最后剩下的节点保持原样
你不能更改节点中的值,只能更改节点本身。
数据范围: 0≤n≤2000 ,1≤k≤2000 ,链表中每个元素都满足0≤val≤1000
要求空间复杂度 O(1),时间复杂度 O(n)
例如:
给定的链表是1→2→3→4→5
对于 k = 2k=2 , 你应该返回 2→1→4→3→5
对于 k = 3k=3 , 你应该返回 3→2→1→4→5
3.2思路以及代码
使用栈的帮助,不需要太多的思路
using System;
using System.Collections;
using System.Collections.Generic;
/*
public class ListNode
{
public int val;
public ListNode next;
public ListNode (int x)
{
val = x;
}
}
*/
class Solution {
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param head ListNode类
* @param k int整型
* @return ListNode类
*/
public ListNode reverseKGroup (ListNode head, int k) {
// write code here
if (k <= 1 || head == null)
{
return head;
}
Stack st = new Stack();
ListNode newhead = new ListNode(-1);
newhead.next=head;
ListNode res=newhead;
while (head != null)
{
st.Push(head);
head = head.next;
if(st.Count==k)
{
while (st.Count > 0)
{
newhead.next = (ListNode)st.Peek();
st.Pop();
newhead = newhead.next;
}
newhead.next = head;//最后剩余不足k个的,不翻转,所以让他指向原来的位置
}
}
return res.next;
}
}
四 合并两个排序的链表
4.1题目
输入两个递增的链表,单个链表的长度为n,合并这两个链表并使新链表中的节点仍然是递增排序的。
如输入{1,3,5},{2,4,6}时,合并后的链表为{1,2,3,4,5,6},所以对应的输出为{1,2,3,4,5,6}
4.2思路以及代码
此题比较简单,我用了一个current去判断已经排好的顺序
/*
public class ListNode
{
public int val;
public ListNode next;
public ListNode (int x)
{
val = x;
}
}*/
class Solution
{
public ListNode Merge(ListNode pHead1, ListNode pHead2)
{
// write code here
ListNode head=new ListNode(-1);
ListNode current=head;
while(pHead1!=null&&pHead2!=null){
if(pHead1.val>pHead2.val){
current.next=pHead2;
pHead2=pHead2.next;
}else{
current.next=pHead1;
pHead1=pHead1.next;
}
current=current.next;
}
if(pHead1!=null){
current.next=pHead1;
}else{
current.next=pHead2;
}
return head.next;
}
}