之前数据结构其实学得不错,A+,但是已经快忘光了,所以重修一下(记录起来就不怕忘得快了,嘿嘿)
算法是用于解决特定问题的一系列的执行步骤
斐波那契数列
斐波那契数列(0,1,1,2,3,5,8,…),从第三项开始,每项等于前两项之和
求第n个斐波那契数的代码
方法一:
public static int fib1(int n){
if(n<=1)
return n;
return fib1(n-1) + fib1(n-2);
}
方法二:
public static int fib2(int n){
if(n<=1)
return n;
int first = 0;
int second = 1;
for(int i=1; i<n-1; i++){ //n从1开始
int sum = first + second;
first = second;
second = sum;
}
return second;
}
忽略常数项后,方法一的时间复杂度为O(2^n),方法二的时间复杂度为O(n)
当n变大时,方法一显然比方法二时间复杂度大得多,递归这种方法能不用最好就不用。
斐波那契数列这个例子就可以证明算法的重要性
数据结构
线性表
数组
局部变量在栈中,new出来的在堆中,java有垃圾回收机制,不用像c++一样需要delete防止内存泄漏
动态数组
假如不用java官方的动态数组,自己设计的话,接口怎么设计?
设计如下:
自己写动态数组,肯定要先处理打印的问题
java中打印其实就是调用toString方法
泛型肯定也是要用的技术
还有一个问题是动态扩容,怎么处理?
处理起来其实很简单,申请新的足够大的堆空间,将原本的元素赋值过去即可。
其他的接口的实现,如add()、remove()等,相信都不是问题。自己写过动态数组类以后,使用java官方的ArrayList就更加随心所欲了。
链表(Linked List)
动态数组有个明显的缺点,可能会造成内存空间的大量浪费,链表则可以做到用到多少申请多少。
链表使用虚拟头结点可以使代码逻辑统一
简单刷几道leetcode链表题目
这几道题都没有虚拟头结点
提交的答案
class Solution {
public ListNode deleteNode(ListNode head, int val) {
if(head.val == val)
return head.next;
if(head.next == null)
return head;
ListNode pre = head;
ListNode cur = head.next;
while(cur.val != val && cur.next != null){
pre = cur;
cur = cur.next;
}
if(cur.val == val)
pre.next = cur.next;
return head;
}
}
删除链表结点需要记录删除结点的前一个结点,或者将删除结点的val改为下一个结点val,并修改next的结点对象
反转链表需要一个newhead,并使用头插法实现反转
提交的答案
class Solution {
public ListNode reverseList(ListNode head) {
ListNode newhead = null;
ListNode tmp;
while(head!=null){
tmp = head.next;
head.next = newhead;
newhead = head;
head = tmp;
}
return newhead;
}
}
提交的答案
public class Solution {
public boolean hasCycle(ListNode head) {
Set<ListNode> set = new HashSet<ListNode>();
while(head!=null){
if(!set.add(head)){
return true;
}
head = head.next;
}
return false;
}
}
ArrayList和LinkedList的时间复杂度分析
双向链表
java官方的LinkedList是双向链表,从JDK1.7开始,LinkedList 由双向循环链表改为双向链表
ArrayList和LinkedList的优缺点对比
单向循环链表
双向循环链表
双向循环链表可解决约瑟夫问题
静态链表
静态链表,了解一下即可
ArrayList的优化思路
ArrayList的优化思路:存储首元素的位置
栈
栈的接口设计
栈的应用-浏览器的前进和后退
leetcode练习
提交的答案
class Solution {
public boolean isValid(String s) {
if(s.isEmpty())
return true;
Stack<Character> stack = new Stack<Character>();
for(char c: s.toCharArray()){
if(c == '('){
stack.push(')');
}
else if(c == '{'){
stack.push('}');
}
else if(c == '['){
stack.push(']');
}
else{
if(stack.empty())
return false;
if(c != stack.pop())
return false;
}
}
if(!stack.empty())
return false;
return true;
}
}