剑指offer-链表下篇
·JZ22 链表中倒数最后K个结点
题目地址
描述
输入一个长度为 n 的链表,设链表中的元素的值为 ai ,输出一个链表,该输出链表包含原链表中从倒数第 k 个结点至尾节点的全部节点。
如果该链表长度小于k,请返回一个长度为 0 的链表。
数据范围:0 <= n <= 10^50, 0 ≤ n ≤ 10 , 0 <=k <= 10^9
要求:空间复杂度 O(n)O(n),时间复杂度 O(n)O(n)
进阶:空间复杂度 O(1)O(1),时间复杂度 O(n)O(n)
示例1
输入:
{1,2,3,4,5},3
返回值:
{3,4,5}
示例2
输入:
{2},8
返回值:
{}
方法一 利用栈解决
先将原链表的结点全部压入栈中,然后把栈中最上面k个结点出栈,出栈的结点串成新的一个链表
import java.util.*;
/*
* public class ListNode {
* int val;
* ListNode next = null;
* public ListNode(int val) {
* this.val = val;
* }
* }
*/
public class Solution {
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param pHead ListNode类
* @param k int整型
* @return ListNode类
*/
public ListNode FindKthToTail (ListNode pHead, int k) {
// write code here
if(k<=0){
return null;
}
List<ListNode> list=new ArrayList<>();
int n=0;
while(pHead != null){
list.add(pHead);
n++;
pHead=pHead.next;
}
if(n<k){
return null;
}
return list.get(n-k);
}
}
方法二 利用双指针求解
思路:设置两个指针,第一个指针先移动k步,然后第二个指针从头开始,此时两个指针同时移动,直到第一个指针指向null。注意,如果第一个指针先移动时,没移动k步就为空的话,直接返回null即可。
代码:
import java.util.*;
/*
* public class ListNode {
* int val;
* ListNode next = null;
* public ListNode(int val) {
* this.val = val;
* }
* }
*/
public class Solution {
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param pHead ListNode类
* @param k int整型
* @return ListNode类
*/
public ListNode FindKthToTail (ListNode pHead, int k) {
// write code here
ListNode first=null;
ListNode second=null;
first=pHead;
for(int i=0;i<k;i++){
if(first == null){
return null;
}
first=first.next;
}
second=pHead;
while(first!=null){
first=first.next;
second=second.next;
}
return second;
}
}
·JZ35 复杂链表的复制
题目地址
描述
输入一个复杂链表(每个节点中有节点值,以及两个指针,一个指向下一个节点,另一个特殊指针random指向一个随机节点),请对此链表进行深拷贝,并返回拷贝后的头结点。(注意,输出结果中请不要返回参数中的节点引用,否则判题程序会直接返回空)。 下图是一个含有5个结点的复杂链表。图中实线箭头表示next指针,虚线箭头表示random指针。为简单起见,指向null的指针没有画出。
示例:
输入:{1,2,3,4,5,3,5,#,2,#}
输出:{1,2,3,4,5,3,5,#,2,#}
解析:我们将链表分为两段,前半部分{1,2,3,4,5}为ListNode,后半部分{3,5,#,2,#}是随机指针域表示。
以上示例前半部分可以表示链表为的ListNode:1->2->3->4->5
后半部分,3,5,#,2,#分别的表示为
1的位置指向3,2的位置指向5,3的位置指向null,4的位置指向2,5的位置指向null
如下图:
示例1
输入:
{1,2,3,4,5,3,5,#,2,#}
返回值:
{1,2,3,4,5,3,5,#,2,#}
方法一 借助额外辅助空间-map
import java.util.*;
/*
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;
}
HashMap<RandomListNode,RandomListNode> map=new HashMap<>();
RandomListNode head=pHead;
while(head!=null){
map.put(head,new RandomListNode(head.label));
head=head.next;
}
for(RandomListNode node:map.keySet()){
map.get(node).next=map.get(node.next);
map.get(node).random=map.get(node.random);
}
return map.get(pHead);
}
}
方法二 不借助辅助空间—左神提供的解法
如下图所示,图中的第一、二、三步,分别对应代码中的步骤一、二、三。
import java.util.*;
/*
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;
RandomListNode next = null;
// 步骤一
while (cur != null) {
next = cur.next;
cur.next = new RandomListNode(cur.label);
cur.next.next = next;
cur = next;
}
cur = pHead;
RandomListNode curCopy = null;
// 步骤二
while (cur != null) {
next = cur.next.next;
curCopy = cur.next;
curCopy.random = cur.random != null ? cur.random.next : null;
cur = next;
}
RandomListNode res = pHead.next;
cur = pHead;
// 步骤三
while (cur != null) {
next = cur.next.next;
curCopy = cur.next;
cur.next = next;
curCopy.next = next != null ? next.next : null;
cur = next;
}
return res;
}
}
·JZ76 删除链表中重复的结点
题目地址
描述
在一个排序的链表中,存在重复的结点,请删除该链表中重复的结点,重复的结点不保留,返回链表头指针。 例如,链表1->2->3->3->4->4->5 处理后为 1->2->5
示例1
输入:
{1,2,3,3,4,4,5}
返回值:
{1,2,5}
代码
思路:遍历链表,并利用HashMap存储值对应出现的次数,再次便利,删除次数1此以上的结点。
import java.util.*;
/*
public class ListNode {
int val;
ListNode next = null;
ListNode(int val) {
this.val = val;
}
}
*/
public class Solution {
public ListNode deleteDuplication(ListNode pHead) {
HashMap<Integer,Integer> map=new HashMap<>();
ListNode now=pHead;
while(now!=null){
if(map.containsKey(now.val)){
map.put(now.val,map.get(now.val)+1);
}else{
map.put(now.val,1);
}
now=now.next;
}
ListNode next=null;
ListNode pre=pHead;
while(pre != null){
if(map.get(pre.val)>1){
pre=pre.next;
}else{
break;
}
}
if(pre==null){
return pre;
}
now=pre.next;
ListNode res=pre;
while(now != null){
if(map.get(now.val)>1){
pre.next=now.next;
now=now.next;
}else{
pre=now;
now=now.next;
}
}
return res;
}
}