1、从尾到头打印链表
题目描述:
输入一个链表,按链表从尾到头的顺序返回一个ArrayList。
思路1:
- 新建一个栈和一个数组,先把链表中的结点全部存入栈内,然后在从栈中push结点进数组,直到栈为空,返回此数组。
代码:
import java.util.ArrayList;
import java.util.Stack;
public class Solution {
public ArrayList<Integer> printListFromTailToHead(ListNode listNode) {
ArrayList<Integer> array = new ArrayList<>();
Stack<Integer> stack = new Stack<>();
ListNode p = listNode;
while(p!=null){
stack.push(p.val);
p = p.next;
}
while(!stack.isEmpty()){
array.add(stack.pop());
}
return array;
}
}
思路2:
- 用递归写
public class Solution {
ArrayList<Integer> arrayList=new ArrayList<Integer>();
public ArrayList<Integer> printListFromTailToHead(ListNode listNode) {
if(listNode!=null){
this.printListFromTailToHead(listNode.next);
arrayList.add(listNode.val);
}
return arrayList;
}
}
2、链表中环的入口结点
题目描述:
输入一个链表,按链表从尾到头的顺序返回一个ArrayList。
思路:
- 定义两个快慢指针,以头结点为起点,快指针每次走两步,慢指针每次走一步。
- 若有环,则快慢指针一定相交于环内,让慢指针回到头结点,这时快慢指针同时都走一步,当相遇时则为环的入口结点。
代码:
/*
public class ListNode {
int val;
ListNode next = null;
ListNode(int val) {
this.val = val;
}
}
*/
public class Solution {
public ListNode EntryNodeOfLoop(ListNode pHead)
{
ListNode fast = pHead;
ListNode slow = pHead;
while(fast!=null&&fast.next!=null){
slow = slow.next;
fast = fast.next.next;
if(slow==fast)
break;
}
if(fast==null||fast.next==null)
return null;
slow= pHead;
while(slow!=fast){
slow = slow.next;
fast = fast.next;
}
return fast;
}
}
3、删除链表中重复的结点
题目描述:
在一个排序的链表中,存在重复的结点,请删除该链表中重复的结点,重复的结点不保留,返回链表头指针。 例如,链表1->2->3->3->4->4->5 处理后为 1->2->5
思路:
- 添加一个为空的头结点,防止出现删除第一个结点的情况
- 两个指针记录前后结点,快指针一直往后遍历。
代码:
/*
public class ListNode {
int val;
ListNode next = null;
ListNode(int val) {
this.val = val;
}
}
*/
public class Solution {
public ListNode deleteDuplication(ListNode pHead)
{
ListNode Head = new ListNode(0);
Head.next = pHead;
ListNode slow = Head;
ListNode fast = pHead;
while(fast!=null){
if(fast.next!=null&&fast.val==fast.next.val){
while(fast.next!=null&&fast.val==fast.next.val)
fast = fast.next;
slow.next = fast.next;
fast = fast.next;
}
else{
slow = slow.next;
fast = fast.next;
}
}
return Head.next;
}
}
4、链表中倒数第k个结点
题目描述:
输入一个链表,输出该链表中倒数第k个结点。
思路:
- 定义两个快慢指针分别在头结点,让快指针先走k步,定义一个大循环,循环次数为n,剩下的n-k步让慢指针走,则慢指针为链表中的倒数第k个结点。
代码:
/*
public class ListNode {
int val;
ListNode next = null;
ListNode(int val) {
this.val = val;
}
}*/
public class Solution {
public ListNode FindKthToTail(ListNode head,int k) {
ListNode fast = head;
ListNode slow = head;
int i=0;
if(head==null)
return null;
while(i!=k-1){
fast = fast.next;
i++;
if(fast==null)
return null;
}
while(fast.next!=null){
slow = slow.next;
fast = fast.next;
}
return slow;
}
}
5、反转链表
题目描述:
输入一个链表,反转链表后,输出新链表的表头。
思路:
- 就是头插法,把新的头节点 截取下来 然后头插
代码:
/*
public class ListNode {
int val;
ListNode next = null;
ListNode(int val) {
this.val = val;
}
}*/
//反序的过程整个链表分成两个部分,前面的代表已反序,后面的代表待反序,
//反序和待反序
是断开的,所以要注意保存这两条链表的头节点
public class Solution {
public ListNode ReverseList(ListNode head) {
ListNode p = null;//用来保存已经反序的第一个结点
ListNode pnext = head;//用来保存待反序的第一个节点(head 和 next节点)
if(head==null)
return null;
while(head!=null){
pnext = head.next;
head.next = p;
p = head;
head = pnext;
}
return p;
}
}
6、合并两个排序的链表
题目描述:
输入两个单调递增的链表,输出两个链表合成后的链表,当然我们需要合成后的链表满足单调不减规则。
思路:
- 分为非递归方法和递归方法
代码:
非递归:
/*
public class ListNode {
int val;
ListNode next = null;
ListNode(int val) {
this.val = val;
}
}*/
public class Solution {
public ListNode Merge(ListNode list1,ListNode list2) {
//新建一个头节点,用来存合并的链表。
ListNode head = new ListNode(-1);
head.next=null;
ListNode p = head;
while(list1!=null&&list2!=null){
if(list1.val>list2.val){
p.next = list2;
p = list2;
list2 = list2.next;
}
else if(list1.val<=list2.val){
p.next = list1;
p = list1;
list1 = list1.next;
}
}
//把未结束的链表连接到合并后的链表尾部
if(list1==null){
p.next = list2;
}
else{
p.next = list1;
}
return head.next;
}
}
递归:
public ListNode Merge(ListNode list1,ListNode list2) {
if(list1 == null){
return list2;
}
if(list2 == null){
return list1;
}
if(list1.val <= list2.val){
list1.next = Merge(list1.next, list2);
return list1;
}else{
list2.next = Merge(list1, list2.next);
return list2;
}
}
7、复杂链表的复制
题目描述:
输入一个复杂链表(每个节点中有节点值,以及两个指针,一个指向下一个节点,另一个特殊指针指向任意一个节点),返回结果为复制后复杂链表的head。(注意,输出结果中请不要返回参数中的节点引用,否则判题程序会直接返回空)
思路:
- 复制每个节点,如:复制节点A得到A1,将A1插入节点A后面
- 复制随机指针,遍历链表,A1->random = A->random->next;
- 将链表拆分成原链表和复制后的链表
代码:
/*
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 p = pHead;
//复制链表,将每一个结点复制在结点后面
while(p!=null){
RandomListNode cur = new RandomListNode(p.label);
cur.next=p.next;
p.next=cur;
p=cur.next;
}
p = pHead;
//复制链表中的随机指针
while(p!=null){
if(p.random!=null)
p.next.random = p.random.next;
p = p.next.next;
}
//拆分出新旧指针
RandomListNode head = pHead.next;
RandomListNode pcur = head;
p = pHead;
while(p!=null){
p.next=p.next.next;
if(pcur.next!=null)
pcur.next=pcur.next.next;
p=p.next;
pcur=pcur.next;
}
return head;
}
}
8、二叉搜索树与双向链表
题目描述:
输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的双向链表。要求不能创建任何新的结点,只能调整树中结点指针的指向。
思路:
- 二叉树的中序遍历,递归遍历每个结点
代码:
/**
public class TreeNode {
int val = 0;
TreeNode left = null;
TreeNode right = null;
public TreeNode(int val) {
this.val = val;
}
}
*/
public class Solution {
TreeNode phead = null;
TreeNode head = null;
public TreeNode Convert(TreeNode pRootOfTree) {
CobvertTree(pRootOfTree);
return phead;
}
private void CobvertTree(TreeNode root){
if(root==null)
return;
CobvertTree(root.left);
if(head==null){
head = root;
phead = root;
}
else{
head.right = root;
root.left = head;
head = root;
}
CobvertTree(root.right);
}
}
9、两个链表的第一个公共结点
题目描述:
输入两个链表,找出它们的第一个公共结点。
思路:
- 两个链表一定有交点的话,指向短链表指针先走完,然后指向长链表,指向长链表指针后走完,指向短链表。所以,第二次走过,一定会在交点相遇。
代码:
/*
public class ListNode {
int val;
ListNode next = null;
ListNode(int val) {
this.val = val;
}
}*/
public class Solution {
public ListNode FindFirstCommonNode(ListNode pHead1, ListNode pHead2) {
ListNode p = pHead1;
ListNode q = pHead2;
while(p!=q){
if(p==null)
p=pHead2;
else
p=p.next;
if(q==null)
q=pHead1;
else
q=q.next;
}
return p;
}
}