「这是我参与2022首次更文挑战的第29天,活动详情查看:2022首次更文挑战」
3、说一下时间复杂度:1 < O(logn) <O(n) <O(nlogn) <O(n^2) <O(n^k) <O(2^n)
4、斐波那契数列使用的递归的复杂度是O(2^n),因为它可以看作一个颗二叉树,二叉树的高度是 n - 1,由我们的基础知识可以知道,一个高度为k的二叉树最多可以由 2^k - 1个叶子节点,也就是递归过程函数调用的次数,所以时间复杂度为 O(2^n),而空间复杂度就是树的高度 S(n)
二、链表题
链表题主要方法就是两个指针和递归和循环,我们先从这三个角度去思考。
-
003-从尾到头打印链表
办法:递归。不多提醒,你可以直接做出来。时间复杂度O(n)
public static void method(ListNode p) { if(p == null) { return ; } method(p.next); System.out.println(p.val); } -
014-链表中倒数第k个结点
经典的两个指针,一个先动,另外一个等待k。当然java没有指针,他是new两个对象等于原链表,时间复杂度O(n)
public static ListNode method(ListNode p,int k) { ListNode p1 = p; ListNode p2 = p; int i = 0; while(p1 != null && i <= k) { p1 = p1.next; i++; } while(p1 != null && p2 != null) { p1 = p1.next; p2 = p2.next; } return p2.next; }
-
015-反转链表
三个办法,递归,利用栈,循环(这个稍微比较难写),但是复杂度都是O(n)
// 递归办法1 -- 我给出递归主要是因为我发现我不是很习惯递归返回一个值,下面这个递归是没有返回值的 // 我貌似比较喜欢全局变量,也没有错 public static ListNode res = new ListNode(0); public static ListNode ReverseList(ListNode listNode) { ListNode a = res; digui(listNode); return a.next; } public static void digui(ListNode listNode) { if(listNode != null) { digui(listNode.next); res.next = new ListNode(listNode.val); res = res.next; } } // 递归办法2 --有返回值的 public static ListNode res; public static ListNode ReverseList(ListNode listNode) { ListNode a = digui(listNode); return res.next; } public static ListNode digui(ListNode listNode) { if(listNode != null) { ListNode res = digui(listNode.next); // 这一步,你似乎不习惯递归返回值 res.next = new ListNode(listNode.val); return res.next; // 因为一定要把这个东西返回,不然没有意义 }else { ListNode temp = new ListNode(0); // 因为只会进入这里一次 res = temp; return temp; } }循环算法,我放一张图:
这个就是中间状态,pre,next,head已经就位。但是正如我文章开头总结的一样,如果考虑最开始的pre=null思考怎么写代码,实在难以理解,无法下手。可以直接从下图的状态开始写,这个时候,我们要做的就是让head指向pre,pre移动到head的位置,next和head都移动到3的位置上。
public static ListNode method(ListNode p) {
ListNode pre = null;
ListNode head = p;
ListNode next = null;
while(head != null) {
next = head.next;
head.next = pre;
pre = head;
head = next;
}
return pre;
}