import java.util.ArrayList; import java.util.Stack; /** * 输入一个链表,按链表从尾到头的顺序返回一个ArrayList。 */ public class JZ003PrintListFromTailToHead { /** * 本题很简单,因为是从尾到头的开始答应,那应该首先想到的是栈 Stack * @param listNode * @return */ public ArrayList<Integer> printListFromTailToHead(ListNode listNode) { ArrayList<Integer> arrayList = new ArrayList<>(); Stack<Integer> stack = new Stack<>(); ListNode curNode = listNode; while (curNode != null) { int val = curNode.val; stack.push(val); curNode = curNode.next; } while (!stack.isEmpty()) { arrayList.add(stack.pop()); } return arrayList; } public static void main(String[] args) { // ListNode listNode = new ListNode(1); } /* 从尾到头打印链表 总结: 1、从尾到头,首先想到的是栈 Stack,(Stack、ArrayList、LinkedList、Vector等的区别) 2、本地考察链表,需要注意链表和数组的区别: - 链表是一种动态数据结构,是因为在创建链表时,无须知道链表的长度。当插入一个节点时,只需要为新节点分配内存,然后调整引用的指向 来确保新节点被链接到链表中。内存分配不是在创建链表是一次性完成,而是每次添加一个节点分配一次内存。由于没有闲置的内存,链表中的 空间比数组高。 3、链表基本的使用: - addNode() 添加节点 - deleteNode() 删除节点 - lengthNode() 返回节点的长度 - reverseList() 链表反转 - searchMid() 查找单聊表的中间节点 - searchEndElem() 查找倒数第k个元素 - orderList() 排序 - printNode() 打印节点 - isPool() 判断链表是否有环,单链表有环时(两个引用,一个快,一个慢) - findLoopPort() 找出链表环的入口 (这个有点难,需要数学公式的推到,具体参考:https://blog.csdn.net/weixin_40879743/article/details/90646399) */ /** * 添加节点 * @param listNode * @param data */ public static void addNode(ListNode listNode, int data) { ListNode newNode = new ListNode(data); if (listNode == null) { listNode = newNode; } ListNode curNode = listNode; while (curNode.next != null) { curNode = curNode.next; } curNode.next = newNode; } /** * 删除节点 * @param listNode * @param index * @return */ public static boolean deleteNode(ListNode listNode, int index) { if (index < 1 || index > lengthNode(listNode)) { return false; } if (index == 1) { listNode = listNode.next; return true; } int i = 2; ListNode preNode = listNode; ListNode curNode = preNode.next; while (curNode != null) { if (i == index) { preNode.next = curNode.next; return true; } preNode = curNode; curNode = curNode.next; i++; } return false; } /** * 返回节点的长度 * @param listNode * @return */ public static int lengthNode(ListNode listNode) { int len = 0; ListNode curNode = listNode; while (curNode != null) { len++; curNode = curNode.next; } return len; } /** * 链表反转 * @param listNode */ public static void reverseList(ListNode listNode) { ListNode preNode = null; // 头节点 ListNode curNode = listNode; // 前一个节点 while (curNode != null) { ListNode nextNode = curNode.next; // 保存下一个节点 curNode.next = preNode; // 链表的反转 preNode = curNode; // 前节点后移 curNode = nextNode; // 当前节点后移 } listNode = preNode; } /** * 查找单聊表的中间节点 * @param listNode * @return */ public static ListNode searchMid(ListNode listNode) { ListNode slowNode = listNode; ListNode quickNode = listNode; // quickNode.next == null 表示链表的个数为奇数,快引用已经走到了最后一个节点 // quickNode.next.next == null 表示链表的个数为偶数,快引用已经走到了倒数第二个节点 // 链表为奇数,返回的是中间节点 // 链表为偶数,返回的是中间两个节点的前一个节点 while (quickNode.next != null && quickNode.next.next != null) { slowNode = slowNode.next; quickNode = quickNode.next.next; } return slowNode; } /** * 查找倒数第k个元素 * @param listNode * @param k * @return */ public static ListNode searchEndElem(ListNode listNode, int k) { if (k < 1 || k > lengthNode(listNode)) { return null; } ListNode firstNode = listNode; ListNode secondNode = listNode; for (int i = 0; i < k - 1; i++) { firstNode = firstNode.next; } while (firstNode.next != null) { firstNode = firstNode.next; secondNode = secondNode.next; } return secondNode; } /** * 排序 选择排序,时间复杂度 O(n^2) * @param listNode * @return */ public static ListNode orderList(ListNode listNode) { ListNode curNode = listNode; while (curNode != null) { ListNode nextNode = curNode.next; while (nextNode != null) { if (curNode.val > nextNode.val) { int tmp = curNode.val; curNode.val = nextNode.val; nextNode.val = tmp; } nextNode = nextNode.next; } curNode = curNode.next; } return listNode; } /** * 打印节点 * @param listNode */ public static void printNode(ListNode listNode) { ListNode curNode = listNode; while (curNode != null) { System.out.print(curNode.val + " "); curNode = curNode.next; } System.out.println(); } /** * 判断链表是否有环,单链表有环时(两个引用,一个快,一个慢) * @param listNode * @return */ public static boolean isPool(ListNode listNode) { if (listNode == null || listNode.next == null) { return false; } ListNode slowNode = listNode; ListNode fastNode = listNode; while (fastNode.next != null && fastNode.next.next != null) { slowNode = slowNode.next; fastNode = fastNode.next.next; if (slowNode == fastNode) { return true; } } return false; } /** * 找出链表环的入口 * @param listNode * @return */ public static ListNode findLoopPort(ListNode listNode) { if (listNode == null && listNode.next == null) { return null; } ListNode slowNode = listNode; ListNode fastNode = listNode; while (fastNode.next != null && fastNode.next.next != null) { slowNode = slowNode.next; fastNode = fastNode.next.next; if (slowNode == fastNode) { break; } } if (fastNode.next == null || fastNode.next.next == null) { return null; } fastNode = listNode; while (fastNode != slowNode) { fastNode = fastNode.next; slowNode = slowNode.next; } return slowNode; } }
剑指Offer 从尾到头打印列表
最新推荐文章于 2022-05-17 22:34:04 发布