文章目录
剑指Offer_6:从尾到头打印链表
题目:输入一个链表,按链表从尾到头的顺序返回一个ArrayList。
思路1:使用栈,利用栈的先进后出的特点,将链表的节点压入栈中,然后再弹出。
class ListNode {
int val;
ListNode next = null;
ListNode(int val) {
this.val = val;
}
}
public class Solution {
public ArrayList<Integer> printListFromTailToHead(ListNode listNode) {
Stack<Integer> stack = new Stack<>();
ArrayList<Integer> list = new ArrayList<>();
while(listNode!=null){
stack.push(listNode.val);
listNode = listNode.next;
}
//将栈顶的元素弹出
while (!stack.isEmpty()){
list.add(stack.pop()) ;
}
return list;
}
}
思路2:使用递归来实现。
public class Solution {
public static ArrayList<Integer> printListFromTailToHead(ListNode listNode) {
ArrayList<Integer> list = new ArrayList<>();
if(listNode==null){
return list;
}
return dp(list,listNode);
}
private static ArrayList<Integer> dp(ArrayList<Integer> list, ListNode listNode) {
//递归的条件
if(listNode.next!=null){
list = dp(list,listNode.next);
}
//递归条件不满足时要做的事
list.add(listNode.val);
return list;
}
}
剑指offer_6(LeetCode):从尾到头打印链表
题目:输入一个链表的头节点,从尾到头反过来返回每个节点的值(用数组返回)
class Solution {
public int[] reversePrint(ListNode head) {
Stack<Integer> stack = new Stack<>();
ListNode temp = head;
while(temp!=null) {
stack.push(temp.val);
temp = temp.next;
}
int[] arr = new int[stack.size()];
for(int i=0;i<arr.length;i++){
arr[i] = stack.pop();
}
return arr;
}
}
剑指Offer_53:链表中环的入口节点
题目:给一个链表,若其中包含环,请找出该链表的环的入口结点,否则,输出null。
public class Solution {
public ListNode EntryNodeOfLoop(ListNode pHead) {
/**
* 1、先判断链表是否成环
*/
if(pHead==null || pHead.next==null){
return null;
}
ListNode slow = pHead;
ListNode fast = pHead;
boolean flag = false;
while (fast!=null && fast.next!=null){
slow = slow.next;
fast = fast.next.next;
if(fast == slow){
flag = true;
break;
}
}
if(flag){
/**
* 2、计算环的长度,让快指针多走一圈就可以得到环的长度,相遇就可以
*/
int length = 1;
fast = fast.next;
while (slow!=fast){
fast = fast.next;
length++;
}
/**
* 3、找到环的入口节点:
* 让快慢指针都从头开始走,因为快指针比慢指针多走环的长度个节点
* 让快指针先走环的长度个节点,然后两个指针走的节点就一样了,这样快慢节点肯定会相遇
*/
fast = slow = pHead;
for(int i=0;i<length;i++){
fast = fast.next;
}
while (slow!=fast){
slow = slow.next;
fast = fast.next;
}
return fast;
}else{
return null;
}
}
}
剑指Offer_18:删除链表中重复的节点
题目:在一个排序的链表中,存在重复的结点,请删除该链表中重复的结点,重复的结点不保留,返回链表头指针。 例如,链表1->2->3->3->4->4->5 处理后为 1->2->5
public class Solution {
public ListNode deleteDuplication(ListNode pHead) {
ListNode dummuy = new ListNode(0);
dummuy.next = pHead;
ListNode cur = dummuy;
while (cur.next!=null && cur.next.next!=null){
if(cur.next.val==cur.next.next.val){
ListNode tmp = cur.next;
while (tmp!=null && tmp.next!=null && tmp.val==tmp.next.val){
tmp = tmp.next;
}
cur.next = tmp.next;
}else{
cur = cur.next;
}
}
return dummuy.next;
}
}
剑指Offer_22:链表中倒数第K个节点
题目:输入一个链表,输出该链表中倒数第k个结点。
public class Solution {
public ListNode FindKthToTail(ListNode head,int k) {
/**
* 1、使用快慢指针:让两个指针fast和slow都指向头指针
* 2、让fast指针先走k个节点
* 3、然后让fast和slow同时走
* 4、当fast走到链表结尾时,slow指向的就是倒数第k个节点
*/
ListNode fast = head;
ListNode slow = head;
for(int i=0;i<k;i++){
if(fast==null){
return null;
}
fast = fast.next;
}
while (fast!=null){
fast = fast.next;
slow = slow.next;
}
return slow;
}
}
剑指Offer_24:反转链表
题目:输入一个链表,反转链表后,输出新链表的表头。
public class Solution {
public ListNode ReverseList(ListNode head) {
/**
* 进性边界条件判断:
* 1、如果节点为null,直接返回该节点
* 2、如果只有一个节点,直接返回该节点
*/
if(head==null || head.next==null){
return head;
}
/**
* 1、定义一个临时节点cur一直指向cur的下一个节点,保证链表不会断掉
* 2、定义一个辅助节点遍历这个链表,刚开始指向head
* 3、让cur.next指向pre,然后让pre指向cur
* 4、让cur和tmp同时后移
*/
ListNode pre = null;
ListNode tmp = null;
ListNode cur = head;
while (cur!=null){
tmp = cur.next;//tmp后移
cur.next = pre;
pre = cur;
cur = tmp;//cur后移
}
return pre;
}
}
剑指Offer_25:合并两个排序的链表
题目:输入两个单调递增的链表,输出两个链表合成后的链表,当然我们需要合成后的链表满足单调不减规则。
public class Solution {
public ListNode Merge(ListNode list1,ListNode list2) {
/**
* 1、定义一个伪节点dum,连接合并后的新链表
* 2、因为头结点不能动,定义一个辅助指针cur,遍历合并后的新链表
* 3、遍历两个链表,比较节点的值,将较小的节点加到新链表节点后面
*/
ListNode dum = new ListNode(0);
ListNode cur = dum;
while (list1!=null && list2!=null){
if(list1.val<=list2.val){
cur.next = list1;
list1 = list1.next;
}else{
cur.next = list2;
list2 = list2.next;
}
cur = cur.next;
}
/**
* 如果链表1或2中有剩余节点就添加到新链表的结尾
*/
if(list1!=null){
cur.next = list1;
}else if(list2!=null){
cur.next = list2;
}
return dum.next;
}
}
剑指Offer_36:二叉搜索树与双向链表
题目:输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的双向链表。要求不能创建任何新的结点,只能调整树中结点指针的指向。
public class Solution {
/**
* 中序遍历的顺序就是递增的,利用这个性质
*/
public TreeNode Convert(TreeNode pRootOfTree) {
if(pRootOfTree==null){
return null;
}
ArrayList<TreeNode> list = new ArrayList<>();
inOrder(pRootOfTree,list);
/**
* 将集合中的节点变成双向链表:
* 1、第一个节点的左子节点为null
* 2、定义一个辅助指针cur,遍历节点
* 3、遍历每个节点,将其左子节点设为前驱节点,后一个节点设为后继节点
* 3、让cur后移
*/
TreeNode head = list.get(0);
head.left = null;
TreeNode cur = head;
for(int i=1;i<list.size();i++){
cur.right = list.get(i);
list.get(i).left = cur;
cur = cur.right;
}
return head;
}
/**
* 这个方法的作用就是中序遍历,并将遍历的结果存入list集合中
*/
private void inOrder(TreeNode pRootOfTree, ArrayList<TreeNode> list) {
//递归的边界条件
if(pRootOfTree == null){
return;
}
inOrder(pRootOfTree.left,list);
list.add(pRootOfTree);
inOrder(pRootOfTree.right,list);
}
}
剑指Offer_52:两个链表的第一个公共节点
题目:输入两个链表,找出它们的第一个公共节点。
本题有两种解题方法:
思路1:两个指针,一个指针指向A,一个指针指向B,让他们遍历两个链表,每遍历一个节点就比较一次,判断是不是相等,相等就退出循环,如果A先走到链表的尾部,就从该链表的头开始走,如果B走到了链表的尾部,也从该链表的头开始走,最终两个指针一定会相遇在第一个公共节点。(不断减小两者的节点差)
public class Solution {
public ListNode FindFirstCommonNode(ListNode pHead1, ListNode pHead2) {
ListNode cur1 = pHead1;
ListNode cur2 = pHead2;
while (cur1!=cur2){
if(cur1==null){
cur1 = pHead1;
}else{
cur1 = cur1.next;
}
if(cur2==null){
cur2 = pHead2;
}else{
cur2 = cur2.next;
}
}
return cur1;
}
}
思路2:两个指针,一个指针指向A,一个指针指向B,让他们遍历两个链表,每遍历一个节点就比较一次,判断是不是相等,相等就退出循环,如果A先走到链表的尾部,就从B链表的头开始走,如果B走到了链表的尾部,从A链表的头开始走,最终两个指针一定会相遇在第一个公共节点。
public class Solution {
public ListNode FindFirstCommonNode(ListNode pHead1, ListNode pHead2) {
ListNode cur1 = pHead1;
ListNode cur2 = pHead2;
while (cur1!=cur2){
if(cur1==null){
cur1 = pHead2;
}else{
cur1 = cur1.next;
}
if(cur2==null){
cur2 = pHead1;
}else{
cur2 = cur2.next;
}
}
return cur1;
}
}