102、二叉树的层序遍历
BFS+DFS
队列和BFS是相辅相成的
BFS Python Code:
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
#from collections import deque
class Solution:
def levelOrder(self, root: TreeNode) -> List[List[int]]:
#BFS
#N is the size of nums
#Time Complexity:O(N)
#Space Complexity: O(N)
result = []
if root is None:
return result
q = deque([])
q.append(root)
while(len(q)>0):
size = len(q)
ls = []
while size > 0:
cur = q.popleft()
ls.append(cur.val)
if cur.left is not None:
q.append(cur.left)
if cur.right is not None:
q.append(cur.right)
size = size - 1
result.append(ls[:])
return result
size = 1
cur: TreeNode{val: 3, left: TreeNode{val: 9, left: None, right: None}, right: TreeNode{val: 20, left: TreeNode{val: 15, left: None, right: None}, right: TreeNode{val: 7, left: None, right: None}}}
size = 2
cur: TreeNode{val: 9, left: None, right: None}
cur: TreeNode{val: 20, left: TreeNode{val: 15, left: None, right: None}, right: TreeNode{val: 7, left: None, right: None}}
size = 2
cur: TreeNode{val: 15, left: None, right: None}
cur: TreeNode{val: 7, left: None, right: None}
.
Python中的deque:
deque模块是python标准库collections中的一项,它提供了两端都可以操作的序列,其实就是双向队列,可以从左右两端增加元素,或者是删除元素。如果设置了最大长度,非输入端的数据会逐步移出窗口。
BFS JAVA Code:
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
public List<List<Integer>> levelOrder(TreeNode root) {
//BFS
//N is the size if nums
//Time Complexity:O(N)
//Space Complexity:O(N)
List<List<Integer>> result = new ArrayList<>();
if(root == null){
return result;
}
Queue<TreeNode> q = new LinkedList<>();
q.add(root);
while(q.size()>0){
int size = q.size();
ArrayList<Integer> list = new ArrayList<>();
while(size>0){
TreeNode cur = q.poll();
list.add(cur.val);
if(cur.left != null){
q.add(cur.left);
}
if(cur.right != null){
q.add(cur.right);
}
size--;
}
result.add(new ArrayList<>(list));
}
return result;
}
}
DFS Python Code:
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution:
def levelOrder(self, root: TreeNode) -> List[List[int]]:
#DFS
#N is the size of tree
#H is the heught of tree
#Time Complexity:O(N)
#Space Complexity:O(N)
result = []
if root is None:
return result
self.dfs(root,result,0)
return result
def dfs(self,node,result,level):
if node is None:
return
if level > len(result)-1:
result.append([])
result[level].append(node.val) #重点
if node.left is not None:
self.dfs(node.left,result,level+1)
if node.right is not None:
self.dfs(node.right,result,level+1)
DFS JAVA Code:
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
public List<List<Integer>> levelOrder(TreeNode root) {
//DFS
//N is the size of tree
//H is the height of tree
//Time Complexity:O(N)
//Space Complexity:O(N)
List<List<Integer>> result =new ArrayList<>();
if (root == null){
return result;
}
dfs(root,result,0);
return result;
}
private void dfs(TreeNode node,List<List<Integer>> result,int level){
if(node == null){
return;
}
if(level>result.size()-1){
result.add(new ArrayList<>());
}
result.get(level).add(node.val);
if(node.left != null){
dfs(node.left,result,level+1);
}
if(node.right != null){
dfs(node.right,result,level+1);
}
}
}
d=deque(maxlen=5)
for i in range(10):
d.append(str(i))
###################输出####################
d=deque([‘5’, ‘6’, ‘7’, ‘8’, ‘9’], maxlen=5)。
一、deque入队和出队
deque 类中实现了单个数据入队,将一个可迭代对象入队,将数据插入指定位置的方法。
1单个数据入队
# coding=utf-8
import collections
queue = collections.deque()
queue.append('a')
queue.append('b')
queue.append('c')
print(queue)
#####################输出###########################
deque(['a', 'b', 'c'])
####################################################
queue.appendleft('A')
queue.appendleft('B')
print(queue)
####################输出############################
deque(['B', 'A', 'a', 'b', 'c'])
###################################################
append(item),添加一个数据到队列的尾部。与列表的append()方法功能相似。
appendleft(item),添加一个数据到队列的头部。与append()的添加方向相反。
2. 可迭代对象入队
queue.extend(['D', 'E'])
queue.extendleft(['c', 'd'])
print(queue)
#####################################输出
deque(['d', 'c', 'B', 'A', 'a', 'b', 'c', 'D', 'E'])
extend(iterable),将一个可迭代对象中的数据按顺序添加到队列的尾部。这里要注意,字符串也是可迭代对象,如直接添加字符串’ABC’,会将’A’、‘B’、'C’添加到队列中,因为’ABC’会被当成一个可迭代对象进行迭代,要将’ABC’作为一个整体的字符串添加可以将其放到列表中,添加[‘ABC’]才会符合预期。
extendleft(iterable),将一个可迭代对象中的数据按顺序添加到队列的头部。
3. 指定位置插入数据
queue.insert(3, 'T')
print(queue)
######################################输出
deque(['d', 'c', 'B', 'T', 'A', 'a', 'b', 'c', 'D', 'E'])
insert(index, item),在队列中的指定位置插入一个数据,index为指定的位置索引。
deque 类中实现了队列两端的出队方法。
print(queue.pop())
print(queue.popleft())
print(queue)
###########################################输出
E
d
deque(['c', 'B', 'T', 'A', 'a', 'b', 'c', 'D'])
pop(),将队列尾部的数据弹出,并作为返回值。
popleft(),将队列头部的数据弹出,并作为返回值。
二、deque的copy方法
queue_b = queue.copy()
print(queue)
print(queue_b)
print(id(queue))
print(id(queue_b))
###########################################输出
deque(['c', 'B', 'T', 'A', 'a', 'b', 'c', 'D'])
deque(['c', 'B', 'T', 'A', 'a', 'b', 'c', 'D'])
2502045746056
2502045746992
copy(),拷贝队列。拷贝之后,对原队列进行操作,不会影响到拷贝出来的队列。这个方法要在高于Python3.5的版本才有。
三、deque返回指定值的数量和索引
print(queue.count('b'))
queue.append('b')
print(queue.count('b'))
print(queue.count('z'))
print(queue.index('T'))
##########################################输出
1
2
0
2
count(item),返回队列中指定值的数量,如果值不存在则返回0。
index(item),返回队列中指定值的索引,如果值不存在则报错,如果有多个相同的数据则返回从左到右第一个值的索引。
四、deque的翻转和轮转
print(queue)
queue.reverse()
print(queue)
queue.rotate(3)
print(queue)
############################################输出
deque(['c', 'B', 'T', 'A', 'a', 'b', 'c', 'D', 'b'])
deque(['b', 'D', 'c', 'b', 'a', 'A', 'T', 'B', 'c'])
deque(['T', 'B', 'c', 'b', 'D', 'c', 'b', 'a', 'A'])
reverse(),将队列翻转。与列表的reverse()方法功能一样。
rotate(num),对队列中的数据进行轮转。每次轮转是将队尾的数据出队然后从队头入队,相当于先pop()再appendleft(item),retate(num)中传入轮转的次数。
五、deque的删除
print(queue)
queue.remove('T')
print(queue)
queue.clear()
print(queue)
##############################################输出
deque(['T', 'B', 'c', 'b', 'D', 'c', 'b', 'a', 'A'])
deque(['B', 'c', 'b', 'D', 'c', 'b', 'a', 'A'])
deque([])
remove(item),从队列中删除指定的数据,如果指定的数据不存在则报错,如果有多个相同的数据则只会删除从左到右的第一个数据。
clear(),将队列清空。
六、deque指定队列的长度
que = collections.deque(maxlen=5)
que.extend(['a', 'b', 'c', 'd', 'e'])
print(que)
que.append('F')
print(que)
que.appendleft('A')
print(que)
############################################输出
deque(['a', 'b', 'c', 'd', 'e'], maxlen=5)
deque(['b', 'c', 'd', 'e', 'F'], maxlen=5)
deque(['A', 'b', 'c', 'd', 'e'], maxlen=5)
在实例化队列时,可以使用maxlen方法指定队列的长度。为了方便使用,deque类中用property将maxlen方法转换成了属性,并且deque类初始化时可将maxlen作为参数传入。
指定队列的长度后,如果队列已经达到最大长度,此时从队尾添加数据,则队头的数据会自动出队。队头的数据相等于被队尾新加的数据“挤”出了队列,以保证队列的长度不超过指定的最大长度。反之,从队头添加数据,则队尾的数据会自动出队。
Java集合 LinkedList的原理及使用
LinkedList和ArrayList一样是集合List的实现类
一. 定义一个LinkedList
public static void main(String[] args) {
List<String> stringList = new LinkedList<>();
List<String> tempList = new ArrayList<>();
tempList.add("牛魔王");
tempList.add("蛟魔王");
tempList.add("鹏魔王");
tempList.add("狮驼王");
tempList.add("猕猴王");
tempList.add("禺贼王");
tempList.add("美猴王");
List<String> stringList2 = new LinkedList<>(tempList);
}
上面代码中采用了两种方式来定义LinkedList,可以定义一个空集合,也可以传递已有的集合,将其转化为LinkedList。
public class LinkedList<E> extends AbstractSequentialList<E> implements List<E>, Deque<E>, Cloneable, java.io.Serializable{
transient int size = 0;
/**
* Pointer to first node.
* Invariant: (first == null && last == null) ||
* (first.prev == null && first.item != null)
*/
transient Node<E> first;
/**
* Pointer to last node.
* Invariant: (first == null && last == null) ||
* (last.next == null && last.item != null)
*/
transient Node<E> last;
/**
* Constructs an empty list.
*/
public LinkedList() {
}
/**
* Constructs a list containing the elements of the specified
* collection, in the order they are returned by the collection's
* iterator.
*
* @param c the collection whose elements are to be placed into this list
* @throws NullPointerException if the specified collection is null
*/
public LinkedList(Collection<? extends E> c) {
this();
addAll(c);
}
}
LinkedList继承了AbstractSequentialList类,实现了List接口,AbstractSequentialList中已经实现了很多方法,如get(int index)、set(int index, E element)、add(int index, E element) 和 remove(int index),这些方法是我们集合操作时使用最多的,不过这些方法在LinkedList中都已经被重写了,而抽象方法在LinkedList中有了具体实现。因此我们回到LinkedList类
LinkedList类中定义了三个变量:
size:集合的长度
first:双向链表头部节点
last:双向链表尾部节点
private static class Node<E> {
E item;
Node<E> next;
Node<E> prev;
Node(Node<E> prev, E element, Node<E> next) {
this.item = element;
this.next = next;
this.prev = prev;
}
}
LinkedList是通过双向链表实现的,而双向链表就是通过Node类来体现的,类中通过item变量保存了当前节点的值,通过next变量指向下一个节点,通过prev变量指向上一个节点。
二. LinkedList常用方法
- get(int index)
随机读取元素不是LinkedList所擅长的,读取效率比起ArrayList也低得多
public E get(int index) {
checkElementIndex(index);
return node(index).item;
}
/**
* 返回一个指定索引的非空节点.
*/
Node<E> node(int index) {
// assert isElementIndex(index);
if (index < (size >> 1)) {
Node<E> x = first;
for (int i = 0; i < index; i++)
x = x.next;
return x;
} else {
Node<E> x = last;
for (int i = size - 1; i > index; i--)
x = x.prev;
return x;
}
}
get(int index)方法是通过node(int index)来实现的
比较传入的索引参数index与集合长度size/2,如果是index小,那么从第一个顺序循环,直到找到为止;如果index大,那么从最后一个倒序循环,直到找到为止。也就是说越靠近中间的元素,调用get(int index方法遍历的次数越多,效率也就越低,而且随着集合的越来越大,get(int index)执行性能也会指数级降低。因此在使用LinkedList的时候,我们不建议使用这种方式读取数据,可以使用getFirst(),getLast()方法,将直接用到类中的first和last变量。
2. add(E e) 和 add(int index, E element)
LinkedList插入、删除操作效率比较高,以stringList.add(“猪八戒”)为例来看
在LinkedList中我们找到add(E e)方法的源码
public boolean add(E e) {
linkLast(e);
return true;
}
/**
* 设置元素e为最后一个元素
*/
void linkLast(E e) {
final Node<E> l = last;
final Node<E> newNode = new Node<>(l, e, null);
last = newNode;
if (l == null)
first = newNode;
else
l.next = newNode;
size++;
modCount++;
}
List的LinkedList—顾名思义是链表,链表的优点增删效率比较高
首先我们看到了LinkedList间接的实现了List接口(说明LinkedList是有list的特性的,add,remove等)、实现了Cloneable(可复制)、Serializable(进行了序列化),除此之外还有一个东西还实现了Queue(队列,说明应该是有队列的一些特性,pop等),这次先不侧重queue的东西,我们主要看LinkedList是如何实现链表的。
//链表的长度
transient int size = 0;
/**
* Pointer to first node.
* Invariant: (first == null && last == null) ||
* (first.prev == null && first.item != null)
*/
//链表的头
transient Node<E> first;
/**
* Pointer to last node.
* Invariant: (first == null && last == null) ||
* (last.next == null && last.item != null)
*/
//链表的尾
transient Node<E> last;
//链表维护的Node的结构
private static class Node<E> {
E item;
Node<E> next;
Node<E> prev;
Node(Node<E> prev, E element, Node<E> next) {
this.item = element;
this.next = next;
this.prev = prev;
}
}
链表维护了一个size、first(头)和last(尾),我们可以看到Node的结构中有个item、next、prev充分说明了此链表是一个双向链表。
public static void main(String[] args){
//初始化linkedList
List<String> linkedList = new LinkedList<>();
//添加元素
linkedList.add("abc");
linkedList.add("bcd");
return;
}
LinkedList就是这样一个节点一个节点关联起来的
` /**
* Removes the element at the specified position in this list. Shifts any
* subsequent elements to the left (subtracts one from their indices).
* Returns the element that was removed from the list.
*
* @param index the index of the element to be removed
* @return the element previously at the specified position
* @throws IndexOutOfBoundsException {@inheritDoc}
*/
public E remove(int index) {
//检查index是否超出范围size
checkElementIndex(index);
//删除指定位置的节点,首先得找到这个节点
return unlink(node(index));
}
//检查index是否正确
private void checkElementIndex(int index) {
if (!isElementIndex(index))
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
/**
* Returns the (non-null) Node at the specified element index.
*/
//返回指定index位置的节点
Node<E> node(int index) {
// assert isElementIndex(index);
//首先去比较index和size >> 1(也就是size的一半),如果比中间数小则从链表头找,否则从尾找
if (index < (size >> 1)) {
Node<E> x = first;
for (int i = 0; i < index; i++)
x = x.next;
return x;
} else {
Node<E> x = last;
for (int i = size - 1; i > index; i--)
x = x.prev;
return x;
}
}
107、二叉树的层序遍历II
数组在前面插一个值,时间复杂度O(N)
链表在前面插一个值,时间复杂度O(1)
BFS Python Code:
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
from collections import deque
class Solution:
def levelOrderBottom(self, root: TreeNode) -> List[List[int]]:
#BFS
#N is the size of tree
#H is the height of tree
#Time Complexity:O(N)
#Space Complexity:O(N)
result = []
if root is None:
return result
q = deque([])
q.append(root)
temp = deque([])
while len(q)>0:
size = len(q)
ls = []
while size > 0:
cur = q.popleft()
ls.append(cur.val)
if cur.left is not None:
q.append(cur.left)
if cur.right is not None:
q.append(cur.right)
size = size - 1
temp.appendleft(ls[:])
result = list(temp)
return result
BFS JAVA Code:
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
public List<List<Integer>> levelOrderBottom(TreeNode root) {
//BFS
//N is the size of tree
//H is the height of tree
//Time Complexity:O(N)
//Space Complexity:O(N)
List<List<Integer>> result = new ArrayList<>();
if(root == null){
return result;
}
Queue<TreeNode> q = new LinkedList<>();
q.add(root);
LinkedList<ArrayList<Integer>> temp = new LinkedList<>();
while(q.size()>0){
int size = q.size();
ArrayList<Integer> list = new ArrayList<>();
while(size>0){
TreeNode cur = q.poll();
list.add(cur.val);
if(cur.left != null){
q.add(cur.left);
}
if(cur.right != null){
q.add(cur.right);
}
size--;
}
temp.addFirst(new ArrayList<>(list));
}
result = (new ArrayList<>(temp));
return result;
}
}
DFS Python Code:
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
from collections import deque
class Solution:
def levelOrderBottom(self, root: TreeNode) -> List[List[int]]:
#N is the size of tree
#H is the height of tree
#Time Complexity:O(N)
#Space Complexity:O(N)
result = []
if root is None:
return result
self.dfs(root,result,0)
result.reverse()
return result
def dfs(self,node,result,level):
if node is None:
return
if level > len(result)-1:
result.append([])
result[level].append(node.val)
if node.left is not None:
self.dfs(node.left,result,level+1)
if node.right is not None:
self.dfs(node.right,result,level+1)
DFS JAVA Code:
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
public List<List<Integer>> levelOrderBottom(TreeNode root) {
//DFS
//N is the size of tree
//H is the height of tree
//Time Complexity:O(N)
//Space Complexity:O(H)
List<List<Integer>> result = new ArrayList<>();
if(root == null){
return result;
}
dfs(root,result,0);
Collections.reverse(result);
return result;
}
private void dfs(TreeNode node, List<List<Integer>> result,int level){
if(node == null){
return;
}
if(level > result.size()-1){
result.add(new ArrayList<>());
}
result.get(level).add(node.val);
if(node.left != null){
dfs(node.left,result,level+1);
}
if(node.right != null){
dfs(node.right,result,level+1);
}
}
}
二叉树:
二叉树 (Binary Tree) 是 n(n ≥ 0) 个结点的有限集合,该集合为空集时称为空二叉树,由一个根结点和两棵互不相交的、分别称为根结点的左子树和右子树的二叉树组成。例如上文作为例子的树结构,由于出现了一个结点有 3 个子树的情况,所以不属于二叉树,而如图所示结构就是二叉树。
对于二叉树来说有以下特点:
二叉树的每个结点至多有两个子树,也就是说二叉树不允许存在度大于 2 的结点;
二叉树有左右子树之分,次序不允许颠倒,即使是只有一棵子树也要有左右之分。
因此对于一棵有 3 个结点的二叉树来说,由于需要区分左右,会有以下五种情况。
特殊的二叉树
斜树
所有结点都只有左(右)子树的二叉树被称为左(右)斜树,同时这个树结构就是一个线性表,如图所示。
满二叉树
满二叉树要求所有的分支结点都存在左右子树,并且所有的叶结点都在同一层上,若满二叉树的层数为 n,则结点数量为 2n-1 个结点,子叶只能出现在最后一层,内部结点的度都为 2,如图所示。
完全二叉树
从定义上来说,完全二叉树是满足若对一棵具有 n 个结点的二叉树按层序编号,如果编号为 i 的结点 (1 ≤ i ≤ n)于同样深度的满二叉树中编号为 i 的结点在二叉树的位置相同的二叉树。这样讲有些繁琐,可以理解为完全二叉树生成结点的顺序必须严格按照从上到下,从左往右的顺序来生成结点,如图所示。
因此我们就不难观察出完全二叉树的特点,完全二叉树的叶结点只能存在于最下两层,其中最下层的叶结点只集中在树结构的左侧,而倒数第二层的叶结点集中于树结构的右侧。当结点的度为 1 时,该结点只能拥有左子树。
性质一 在二叉树的 i 层上至多有 2i-1 个结点(i>=1)
性质二 深度为 k 的二叉树至多有 2k-1 个结点(i>=1)
性质三 对任何一棵二叉树 T,如果其终端结点树为 n0,度为 2 的结点为 n2,则 n0 = n2 + n1
性质四 具有 n 个结点的完全二叉树的深度为 [log2n] + 1 向下取整
性质五 如果有一棵有 n 个结点的完全二叉树(其深度为 [log2n] + 1,向下取整)的结点按层次序编号(从第 1 层到第 [log2n] + 1,向下取整层,每层从左到右),则对任一结点 i(1 <= i <= n)有
1.如果 i = 1,则结点 i 是二叉树的根,无双亲;如果 i > 1,则其双亲是结点 [i / 2],向下取整
2.如果 2i > n 则结点 i 无左孩子,否则其左孩子是结点 2i
3.如果 2i + 1 > n 则结点无右孩子,否则其右孩子是结点 2i + 1
二叉树的存储结构
顺序存储
由于二叉树的结点至多为 2,因此这种性质使得二叉树可以使用顺序存储结构来描述,在使用顺序存储结构时我们需要令数组的下标体现结点之间的逻辑关系。我们先来看完全二叉树,如果我们按照从上到下,从左到右的顺序遍历完全二叉树时,顺序是这样的:
设父结点的序号为 k,则子结点的序号会分别为 2k 和 2k + 1,子结点的序号和父结点都是相互对应的,因此我们可以用顺序存储结构来描述,
用顺序存储结构描述如图所示:
那么对于一般的二叉树呢?我们可以利用完全二叉树的编号来实现,如果在完全二叉树对应的结点是空结点,修改其值为 NULL 即可,例如:
左斜树:
但是我们可以很明显地看到,对于一个斜树,我开辟的空间数远超过实际使用的空间,这样空间就被浪费了,因此顺序存储结构虽然可行,但不合适。
.
链式存储
由于二叉树的每个结点最多只能有 2 个子树,因此我们就不需要使用上述的 3 种表示法来做,可以直接设置一个结点具有两个指针域和一个数据域,那么这样建好的链表成为二叉链表。例如:
再看个例子,上述我描述孩子兄弟表示法的树结构,稍加改动就可以把图示改成二叉树:
结构体定义
typedef struct BiTNode
{
ElemType data; //数据域
ChildPtr *lchild,*rchild; //左右孩子的指针域
//可以开个指针域指向双亲,变为三叉链表
}BiTNode, *BiTree;
二叉树的遍历
递归遍历法
从斐波那契数列说起
我们先不急着开始谈二叉树的遍历,而是先回忆一下我们是怎么利用斐波那契数列实现递归的:
int f(int n)
{
if (n == 0)
return 0;
else
if (n == 1)
return 1;
else
return f(n - 2) + f(n - 1);
}
我们模拟递归函数调用的过程,和二叉树长得是一模一样啊,那么对于二叉树的操作,我们能否用递归来作些文章?
遍历算法
由于二叉树的结点使用了递归定义,也就是结点的拥有自己本身作为成员的成员,这就使得遍历算法可以使用递归实现,而且思路很清晰。
void PreOrderTraverse (BiTree T)
{
if(T == NULL)
return;
//cout << T->data << " " ; //前序遍历
PreOrderTraverse (T->lchild);
//cout << T->data << " " ; //中序遍历
PreOrderTraverse (T->rchild);
//cout << T->data << " " ; //后序遍历
}
可以看到,根据输出语句的位置不同,输出的数据顺序是不一样的,例如如图所示二叉树,3 种顺序的输出顺序为:
前序:先访问根结点,然后先进入左子树前序遍历,再进入右子树前序遍历。
中序:从根结点出发,先进入根结点的左子树中序遍历,然后访问根结点,最后进入右子树中序遍历。
后序:从左到右先叶子后结点的方式进入左、右子树遍历,最后访问根结点。
169、多数元素
排序法+HashMap+分治法
Sort Python Code:
class Solution:
def majorityElement(self, nums: List[int]) -> int:
#sort
#N is the size of nums
#Time Complexity:O(NlogN)
#Space Complexity:O(1)
nums.sort()
half = len(nums)//2
return nums[half]
时间复杂度:因为用了一次排序O(NlogN)
HashMap Python Code:
class Solution:
def majorityElement(self, nums: List[int]) -> int:
#HashMap
#N is the size of nums
#Time Complexity:O(N)
#Space Complexity:O(N)
mapping = {}
for num in nums:
if num not in mapping:
mapping[num] = 0
mapping[num] = mapping.get(num)+1
half = len(nums)//2
for key in mapping.keys():
if mapping[key] > half:
return key
#never research this condition based on problem statement
return -1
Divide & Conquer Python Code:
class Solution:
def majorityElement(self, nums: List[int]) -> int:
#Divide & Conquer
#N is the size of nums
#Time Complexity:O(NlogN)
#Space Complexity:O(lgN)
return self.getMajority(nums,0,len(nums)-1)
def getMajority(self,nums,left,right):
if left == right:
return nums[left]
mid = left + (right-left)//2
leftMajority = self.getMajority(nums,left,mid)
rightMajority = self.getMajority(nums,mid+1,right)
if leftMajority == rightMajority:
return leftMajority
leftCount = 0
rightCount = 0
print('left =',left)
print('right = ',right)
for i in range(left,right+1):
if nums[i] == leftMajority:
leftCount += 1
elif nums[i] == rightMajority:
rightCount += 1
return leftMajority if leftCount > rightCount else rightMajority
Sort JAVA Code:
class Solution {
public int majorityElement(int[] nums) {
//Sort
//N is the size of nums
//Time Complexity:O(NlogN)
//Space Complexity:O(1)
Arrays.sort(nums);
int half = nums.length/2;
return nums[half];
}
}
HashMap JAVA Code:
class Solution {
public int majorityElement(int[] nums) {
//HashMap
//N is the size of nums
//Time Complexity:O(N)
//Space Complexity:O(N)
HashMap<Integer,Integer> map = new HashMap<>();
for(int num:nums){
if(!map.containsKey(num)){
map.put(num,0);
}
map.put(num,map.get(num)+1);
}
int half = nums.length/2;
for(int key:map.keySet()){
if(map.get(key) > half){
return key;
}
}
//can not research this condition based on the problem statement
return -1;
}
}
Divide & Conquer JAVA Code:
class Solution {
public int majorityElement(int[] nums) {
//Divide & Conquer
//N is the size of nums
//Time Complexity:O(NlogN)
//Space Complexity:O(lgN)
return getMajority(nums,0,nums.length-1);
}
//Divide & Conquer
private int getMajority(int[] nums,int left,int right){
if(left == right){
return nums[left];
}
int mid = left + (right - left)/2;
int leftMajority = getMajority(nums,left,mid);
int rightMajority = getMajority(nums,mid+1,right);
if(leftMajority == rightMajority){
return leftMajority;
}
int leftCount = 0;
int rightCount = 0;
for(int i=left;i<=right;i++){
if(leftMajority == nums[i]){
leftCount++;
}
else if(rightMajority == nums[i]){
rightCount++;
}
}
return leftCount>rightCount?leftMajority:rightMajority;
}
}
200、岛屿数量
DFS Python Code:
class Solution:
def numIslands(self, grid: List[List[str]]) -> int:
#DFS
#R is the row of grid
#C is the column of grid
#Time Complexity:O(RC)
#Space Complexity:O(RC)
if(grid is None or len(grid) == 0):
return 0
result = 0
row = len(grid)
col = len(grid[0])
for i in range(0,row):
for j in range(0,col):
if grid[i][j] == '1':
result += 1
self.dfs(grid,i,j,row,col)
return result
def dfs(self,grid,x,y,row,col):
if(x<0 or y<0 or x>=row or y>=col or grid[x][y] == '0'):
return
grid[x][y] = '0'
self.dfs(grid,x-1,y,row,col)
self.dfs(grid,x+1,y,row,col)
self.dfs(grid,x,y-1,row,col)
self.dfs(grid,x,y+1,row,col)
DFS JAVA Code:
class Solution {
public int numIslands(char[][] grid) {
//DFS
//R is the row of grid
//C is the column of grid
//Time Complexity:O(RC)
//Space Complexity:O(RC)
if(grid == null || grid.length == 0){
return 0;
}
int result = 0;
int row = grid.length;
int col = grid[0].length;
for(int i=0;i<row;i++){
for(int j=0;j<col;j++){
if(grid[i][j] == '1'){
result++;
dfs(grid,i,j,row,col);
}
}
}
return result;
}
private void dfs(char[][] grid,int x,int y,int row,int col){
if(x<0 || y<0 || x>=row || y>=col || grid[x][y]=='0'){
return;
}
grid[x][y] = '0';
dfs(grid,x+1,y,row,col);
dfs(grid,x-1,y,row,col);
dfs(grid,x,y+1,row,col);
dfs(grid,x,y-1,row,col);
}
}
BFS Python Code:
class Solution:
def numIslands(self, grid: List[List[str]]) -> int:
#BFS
#R is the row of grid
#C is the column of grid
#Time Complexity:O(RC)
#Space Complexity:O(RC)
if(grid is None or len(grid)==0):
return 0
result = 0
row = len(grid)
col = len(grid[0])
queue = []
for i in range(0,row):
for j in range(0,col):
if grid[i][j] == '1':
result += 1
queue.append([i,j])
grid[i][j] = '0'
while(len(queue)>0):
cur = queue.pop()
x = cur[0]
y = cur[1]
if(x-1>0 and grid[x-1][y]=='1'):
queue.append([x-1,y])
grid[x-1][y] = '0'
if(x+1<row and grid[x+1][y]=='1'):
queue.append([x+1,y])
grid[x+1][y] = '0'
if(y-1>0 and grid[x][y-1]=='1'):
queue.append([x,y-1])
grid[x][y-1] = '0'
if(y+1<col and grid[x][y+1]=='1'):
queue.append([x,y+1])
grid[x][y+1] = '0'
return result
BFS JAVA Code:
class Solution {
public int numIslands(char[][] grid) {
//BFS
//R is row of grid
//C is column of grid
//Time Complexity:O(RC)
//Space Complexity:O(RC)
if(grid == null || grid.length == 0){
return 0;
}
int result = 0;
int row = grid.length;
int col = grid[0].length;
Queue<int[]> queue = new LinkedList<>();
for(int i=0;i<row;i++){
for(int j=0;j<col;j++){
if(grid[i][j] == '1'){
result ++;
queue.add(new int[]{i,j});
grid[i][j] = '0';
while(queue.size() > 0){
int[] cur = queue.poll();
int x = cur[0];
int y = cur[1];
if(x-1>=0 && grid[x-1][y]=='1'){
queue.add(new int[]{x-1,y});
grid[x-1][y] = '0';
}
if(x+1<row && grid[x+1][y]=='1'){
queue.add(new int[]{x+1,y});
grid[x+1][y] = '0';
}
if(y-1>=0 && grid[x][y-1]=='1'){
queue.add(new int[]{x,y-1});
grid[x][y-1] = '0';
}
if(y+1<col && grid[x][y+1]=='1'){
queue.add(new int[]{x,y+1});
grid[x][y+1] = '0';
}
}
}
}
}
return result;
}
}
UnionFind Python Code:
class Solution:
def numIslands(self, grid: List[List[str]]) -> int:
#Union Find
#R is the row of grid
#C is the column of grid
#Time Complexity:O(RC)
#Space Complexity:O(RC)
if grid is None or len(grid) == 0:
return 0
row = len(grid)
col = len(grid[0])
waters = 0
uf = UnionFind(grid)
for i in range(0,row):
for j in range(0,col):
if(grid[i][j]=='0'):
waters += 1
else:
directions = [(0,1),(0,-1),(1,0),(-1,0)]
for x,y in directions:
x = x+i
y = y+j
if x>=0 and y>=0 and x<row and y<col and grid[x][y] == '1':
uf.union(x*col+y,i*col+j)
return uf.getCount()-waters
class UnionFind:
def __init__(self,grid):
row = len(grid)
col = len(grid[0])
self.root = [-1]*(row*col)
self.count = row*col
for i in range(0,row*col):
self.root[i] = i
def find(self,x):
if x == self.root[x]:
return self.root[x]
else:
self.root[x] = self.find(self.root[x])
return self.root[x]
def union(self,x,y):
rootX = self.find(x)
rootY = self.find(y)
if rootX != rootY:
self.root[rootX] = rootY
self.count -= 1
def getCount(self):
return self.count
268、缺失数字 Missing Number
排序法、HashSet法、数学法
Sort Python Code:
class Solution:
def missingNumber(self, nums: List[int]) -> int:
#Sort Solution
#Time Complexity:O(NlogN)
#Space Complexity:O(1)
nums.sort()
for i in range(len(nums)):
if i != nums[i]:
return i
return len(nums)
Hashset Python Code:
class Solution:
def missingNumber(self, nums: List[int]) -> int:
#hashset Solution
#Time Complexity:O(N)
#Space Complexity:O(N)
hashset = set([])
for num in nums:
hashset.add(num)
for i in range(len(nums)+1):
if i not in hashset:
return i
Math Python Code:
class Solution:
def missingNumber(self, nums: List[int]) -> int:
#Math Solution
#the sum of 0-100 : 100 * (100 + 1)/2
#Time Complexity:O(N)
#Space Complexity:O(1)
total_sum = sum(nums)
total = len(nums)*(len(nums)+1)//2
return (total - total_sum)
Sort JAVA Code:
class Solution {
public int missingNumber(int[] nums) {
//Sort Solution
//Time Complexity:O(NlogN)
//Space Complexity:O(1)
Arrays.sort(nums);
for(int i = 0;i < nums.length;i++){
if(i != nums[i]){
return i;
}
}
return nums.length;
}
}
Hashset JAVA Code:
class Solution {
public int missingNumber(int[] nums) {
//hashset
//Time Complexity:O(N)
//Space Complexity:O(N)
HashSet<Integer> set = new HashSet<>();
for(int num:nums){
set.add(num);
}
for(int i=0;i<nums.length;i++){
if(!set.contains(i)){
return i;
}
}
return nums.length;
}
}
Math JAVA Code:
class Solution {
public int missingNumber(int[] nums) {
//Math solution
//the sum from 1 to 100 : 100*(100+1)/2
//Time Complexity:O(N)
//Space Complexity:O(1)
int len = nums.length;
int sum = 0;
for(int num:nums){
sum += num;
}
int total = nums.length*(nums.length+1)/2;
return (total - sum);
}
}
287、寻找重复数----find the duplicate number
1、哈希表法
2、快慢指针法
Hash Table Python Code:
class Solution:
def findDuplicate(self, nums: List[int]) -> int:
#Hash Table
#N is the size of nums
#Time Complexity:O(N)
#Space Complexity:O(N)
if(nums is None and len(nums) == 0):
return 0
mapping = {}
for num in nums:
if num in mapping:
return num
else:
mapping[num] = 1
return 0
Hash Table JAVA Code:
class Solution {
public int findDuplicate(int[] nums) {
//Hash Table
//N is the size of nums
//Time Complexity:O(N)
//Space Complexity:O(N)
if(nums == null || nums.length == 0){
return 0;
}
HashMap<Integer,Integer> map = new HashMap<>();
for(int num:nums){
if(map.containsKey(num)){
return num;
}
else{
map.put(num,1);
}
}
return 0;
}
}
Fast and Slow Pointer Python Code:
class Solution:
def findDuplicate(self, nums: List[int]) -> int:
#Fast and Slow Pointer
#N is the size of nums
#Time Complexity:O(N)
#Spcae Complexity:O(1)
if nums == None and len(nums) == 0:
return 0
slow = 0
fast = 0
slow = nums[slow]
fast = nums[nums[fast]]
while(slow != fast):
slow = nums[slow]
fast = nums[nums[fast]]
fast = 0
while(slow != fast):
slow = nums[slow]
fast = nums[fast]
return slow
Fast and Slow Pointer JAVA Code:
class Solution {
public int findDuplicate(int[] nums) {
//Fast and Slow Pointer
//N is the size of nums
//Time Complexity:O(N)
//Space Complexity:O(1)
if (nums == null || nums.length < 2){
return 0;
}
int slow = 0;
int fast = 0;
do{
slow = nums[slow];
fast = nums[nums[fast]];
}while(slow != fast);
fast = 0;
while(slow != fast){
slow = nums[slow];
fast = nums[fast];
}
return slow;
}
}
递归算法讲解
递归的基本思想就是把规模大的问题转化为规模小的相似的子问题来解决。特别地,在函数实现时,因为解决大问题的方法和解决小问题的方法往往是同一个方法,所以就产生了函数调用它自身的情况,这也正是递归的定义所在。格外重要的是,这个解决问题的函数必须有明确的结束条件,否则就会导致无限递归的情况。
步进表达式:问题蜕变成子问题的表达式
结束条件:什么时候可以不再使用步进表达式
直接求解表达式:在结束条件下能够直接计算返回值的表达式
递归的三要素
1、明确递归终止条件;
2、给出递归终止时的处理办法;
3、提取重复的逻辑,缩小问题规模。
1). 明确递归终止条件
递归就是有去有回,既然这样,那么必然应该有一个明确的临界点,程序一旦到达了这个临界点,就不用继续往下递去而是开始实实在在的归来。换句话说,该临界点就是一种简单情境,可以防止无限递归。
2). 给出递归终止时的处理办法
刚刚说到,在递归的临界点存在一种简单情境,在这种简单情境下,我们应该直接给出问题的解决方案。一般地,在这种情境下,问题的解决方案是直观的、容易的。
3). 提取重复的逻辑,缩小问题规模
在阐述递归思想内涵时谈到,递归问题必须可以分解为若干个规模较小、与原问题形式相同的子问题,这些子问题可以用相同的解题思路来解决。从程序实现的角度而言,我们需要抽象出一个干净利落的重复的逻辑,以便使用相同的方式解决子问题。
递归算法的编程模型
206、反转链表
iterative迭代+recursive递归
一般能用递归的也能用迭代,能用迭代的也能用递归
Iterative Python Code:
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def reverseList(self, head: ListNode) -> ListNode:
#Iterative
#Time Complexity:O(N)
#Space Complexity:O(1)
dummy = ListNode()
dummy.next = head
while(head != None and head.next != None):
dummy_next = dummy.next
temp = head.next
dummy.next = temp
head.next = temp.next
temp.next = dummy_next
return dummy.next
时间复杂度:由于要一个一个遍历,故O(N)
空间复杂度:由于没有用到常量以外的空间O(1)
#####################################
#####################################
#####################################
Recursion Python Code:
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def reverseList(self, head: ListNode) -> ListNode:
#Recursive
#Time Complexity:O(N)
#Space Complexity: O(N)
if not head or not head.next:
return head
p = self.reverseList(head.next)
head.next.next = head
head.next = None
return p
Iterative JAVA Code:
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
class Solution {
public ListNode reverseList(ListNode head) {
//Iterative
//Time Complexity:O(N)
//Space Complexity:O(1)
ListNode dummy = new ListNode();
dummy.next = head;
while(head != null && head.next != null){
ListNode next = head.next;
ListNode temp = dummy.next;
head.next = head.next.next;
dummy.next = next;
next.next = temp;
}
return dummy.next;
}
}
Recursion JAVA Code:
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
class Solution {
public ListNode reverseList(ListNode head) {
//Recursive
//Time Complexity:O(N)
//Space Complexity:O(N)
if(head == null ||head.next == null){
return head;
}
ListNode res = reverseList(head.next);
head.next.next = head;
head.next = null;
return res;
}
}
209、长度最小的子数组
滑动窗口法+双指针法
Brute Force Python Code:
class Solution:
def minSubArrayLen(self, target: int, nums: List[int]) -> int:
#Brute Force
#Time Limit Exceeded
#N is the size of nums
#Time Complexity:O(N^2)
#Space Complexity:O(1)
if nums is None and len(nums)==0:
return 0
size = 1
while(size<=len(nums)):
for i in range(len(nums)-size+1):
total = sum(nums[i:i+size])
if total >= target:
return size
size += 1
return 0
超出时间限制
前缀和
Brute Force JAVA Code:
class Solution {
public int minSubArrayLen(int target, int[] nums) {
//Brute Force
//Time Limit Exceeded
//N is the size of nums
//Time Complexity:O(N^2)
//Space Complexity:O(1)
if(nums == null || nums.length == 0){
return 0;
}
int size = 1;
while(size <= nums.length){
for(int i=0;i<nums.length-size+1;i++){
int total = 0;
for(int j=i;j<i+size;j++){
total += nums[j];
if(total >= target){
return size;
}
}
size++;
}
}
return 0;
}
}
Sliding Window/Two Pointer Python Code:
class Solution:
def minSubArrayLen(self, target: int, nums: List[int]) -> int:
#Sliding Window/Two Pointer
#N is the size of nums
#Time Complexity:O(N)
#Space Complexity:O(1)
if nums is None and len(nums)==0:
return 0
result = len(nums)+1
total = 0
i,j = 0,0
while(j < len(nums)):
total += nums[j]
j += 1
while(total >= target):
result = min(result,j-i)
total -= nums[i]
i += 1
return 0 if result == len(nums)+1 else result
Sliding Window/Two Pointer JAVA Code:
class Solution {
public int minSubArrayLen(int target, int[] nums) {
//Sliding Window/Two Pointer
//N is the size of nums
//Time Complexity:O(N)
//Space Complexity:O(1)
if(nums == null || nums.length == 0){
return 0;
}
int total = 0;
int i = 0;
int j = 0;
int result = nums.length + 1;
while(j < nums.length){
total+= nums[j];
j++;
while(total >= target){
result = Math.min(result,j-i);
total -= nums[i];
i++;
}
}
return result == nums.length + 1 ? 0:result;
}
}
215、数组中第K个最大元素
暴力法+堆排序+快速排序
Sort Python Code:
class Solution:
def findKthLargest(self, nums: List[int], k: int) -> int:
#Sort
#N is the size of nums
#Time Complexity:O(NlogN)
#Space Complexity:O(1)
nums.sort()
return nums[len(nums)-k]
Sort JAVA Code:
class Solution {
public int findKthLargest(int[] nums, int k) {
//Sort
//N is the size of nums
//Time Complexity:O(NlogN)
//Space Complexity:O(1)
Arrays.sort(nums);
return nums[nums.length-k];
}
}
Heap Python Code:
class Solution:
def findKthLargest(self, nums: List[int], k: int) -> int:
#Heap
#N is the size of nums
#Time Complexity:O(NlogK)
#Space Complexity:O(K)
minheap = []
heapify(minheap)
for num in nums:
heappush(minheap,num)
if len(minheap) > k:
heappop(minheap)
return minheap[0]
数组建堆(heapify)
将一个数组调整为最大堆.
根据堆的性质, 只要保证部分有序即可, 即根节点大于左右节点的值. 将数组抽象为一个完全二叉树, 所以只要从最后一个非叶子节点向前遍历每一个节点即可. 如果当前节点比左右子树节点都大, 则已经是一个最大堆, 否则将当前节点与左右节点较大的一个交换, 并且交换过之后依然要递归的查看子节点是否满足堆的性质, 不满足再往下调整. 如此即可完成数组的堆化.
Heap JAVA Code:
class Solution {
public int findKthLargest(int[] nums, int k) {
//Heap
//N is the size of nums
//Time Complexity:O(NlogK)
//Space Complexity:O(K)
//Min Heap
PriorityQueue<Integer> pq = new PriorityQueue<>();
for(int num:nums){
pq.add(num);
if(pq.size() > k){
pq.poll();
}
}
return pq.peek();
}
}
QuickSort Python Code:
import random
class Solution:
def findKthLargest(self, nums: List[int], k: int) -> int:
#Quick Sort
#N is the size of nums
#Time Complexity:O(N)
#Space Complexity:O(logN)
return self.quickSort(nums,0,len(nums)-1,k)
def quickSort(self,nums,l,r,k):
index = self.randomPartition(nums,l,r)
if index == k-1:
return nums[index]
else:
if index > k-1:
return self.quickSort(nums,l,index-1,k)
else:
return self.quickSort(nums,index+1,r,k)
def randomPartition(self,nums,l,r):
i = random.randint(l,r)
nums[i],nums[r] = nums[r],nums[i]
return self.partition(nums,l,r)
def partition(self,nums,l,r):
pivot = nums[r]
rightmost = r
while(l<=r):
while(l<=r and nums[l]>pivot):
l += 1
while(l<=r and nums[r]<=pivot):
r -= 1
if l <= r:
nums[r],nums[l] = nums[l],nums[r]
nums[rightmost],nums[l] = nums[l],nums[rightmost]
return l
Quick Sort JAVA Code:
class Solution {
public int findKthLargest(int[] nums, int k) {
//Quick Sort
//N is the size of nums
//Time Complexity:O(N)
//Space Complexity:O(logN)
return quickSort(nums,0,nums.length-1,k);
}
public int quickSort(int[] nums,int l,int r,int k){
int index = randomParition(nums,l,r);
if(index == k-1){
return nums[index];
}
else{
return index > k-1 ? quickSort(nums,l,index-1,k) : quickSort(nums,index+1,r,k);
}
}
public int randomParition(int[] nums,int l,int r){
int i = (int)(Math.random()*(r-l))+l;
swap(nums,i,r);
return parition(nums,l,r);
}
public void swap(int[] nums,int i,int j){
int temp = nums[i];
nums[i] = nums[j];
nums[j] = temp;
}
public int parition(int[] nums,int l,int r){
int pivot = nums[r];
int rightmost = r;
while(l <= r){
while(l <= r && nums[l] > pivot){
l++;
}
while(l <= r && nums[r] <= pivot){
r--;
}
if(l <= r){
swap(nums,l,r);
}
}
swap(nums,l,rightmost);
return l;
}
}
217、存在重复元素
set / dict(Hashmap(JAVA))
set:元素唯一,加入重复的数进去里面也只有一个那个数
dict(Hashmap):计算每个元素出现的次数
排序法+set方法+字典法(HashMap)
HashTable:set方法+字典法(HashMap)
自己编写的Sorting Python Code:
class Solution:
def containsDuplicate(self, nums: List[int]) -> bool:
if nums == None and len(nums)==0:
return False
nums.sort()
for i in range(0,len(nums)-1):
if(nums[i]==nums[i+1]):
return True
return False
Sorting Python Code:
class Solution:
def containsDuplicate(self, nums: List[int]) -> bool:
#Sorting
#Time Complexity:O(NlogN)
#Space Complexity:O(1)
if(len(nums)==0):
return False
nums.sort()
prev = nums[0]
for i in range(1,len(nums)):
if prev == nums[i]:
return True
else:
prev = nums[i]
return False
Set Solution Python Code:
class Solution:
def containsDuplicate(self, nums: List[int]) -> bool:
#Set Solution
#Time Complexity:O(N)
#Space Complexity:O(N)
if(len(nums)==0):
return False
HashMap = set(nums)
return False if len(HashMap)==len(nums) else True
HashMap Python Code:
class Solution:
def containsDuplicate(self, nums: List[int]) -> bool:
#HashMap
#Time Complexity:O(N)
#Space Complexity:O(N)
if len(nums)==0:
return False
mapping = {}
for num in nums:
if num not in mapping:
mapping[num] = 1
else:
mapping[num] = mapping.get(num) + 1
for v in mapping.values():
if v > 1:
return True
return False
Sorting JAVA Code:
class Solution {
public boolean containsDuplicate(int[] nums) {
//Sorting
//Time Complexity:O(NlogN)
//Space Complexity:O(1)
if(nums == null && nums.length == 0){
return false;
}
Arrays.sort(nums);
int prv = nums[0];
for(int i=1;i<nums.length;i++){
if(prv == nums[i]){
return true;
}
else{
prv = nums[i];
}
}
return false;
}
}
Set JAVA Code:
class Solution {
public boolean containsDuplicate(int[] nums) {
//Set Solution
//Time Complexity:O(N)
//Space Complexity:O(N)
if(nums == null && nums.length == 0){
return false;
}
HashSet<Integer> set = new HashSet<>();
for(int num : nums){
set.add(num);
}
return set.size() == nums.length ? false : true;
}
}
HashMap JAVA Code:
class Solution {
public boolean containsDuplicate(int[] nums) {
//HashMap
//Time Complexity:O(N)
//Space Complexity:O(N)
if(nums == null && nums.length == 0){
return false;
}
HashMap<Integer,Integer> map = new HashMap<>();
for(int num : nums){
if(map.containsKey(num)){
map.put(num,map.get(num)+1);
}
else{
map.put(num,1);
}
}
for(int k : map.keySet()){
if(map.get(k) > 1){
return true;
}
}
return false;
}
}
231、2的幂
二分查找法–>循环
位操作–>无循环,无递归
Binary Search Python Code:
class Solution:
def isPowerOfTwo(self, n: int) -> bool:
#Binary search
#Time Complexity:O(logN)
#Space Complexity:O(1)
#may be time out
if n < 1:
return false
start = 0
end = n
while(start <= end):
mid = start + (end - start)//2
result = pow(2,mid)
if(result == n):
return True
elif(result > n):
end = mid - 1
elif(result < n):
start = mid + 1
return False
/:浮点数除法
//:整数除法
Binary Search JAVA Code:
class Solution {
public boolean isPowerOfTwo(int n) {
//Binary search
//Time Complexity:O(logN)
//Space Complexity:O(1)
if(n == 0){
return false;
}
int start = 0;
int end = n;
while(start <= end){
int mid = start + (end - start)/2;
long result = (long) Math.pow(2,mid);
if(result == n){
return true;
}
if(result > n){
end = mid - 1;
}
if(result < n){
start = mid + 1;
}
}
return false;
}
}
Bit Manipulation Python Code:
class Solution:
def isPowerOfTwo(self, n: int) -> bool:
#Bit Manipulation
#Time Complexity:O(1)
#Space Complexity:O(1)
if(n==0):
return False
return (n & (n-1)) == 0
Bit Manipulation JAVA Code:
class Solution {
public boolean isPowerOfTwo(int n) {
//Bit Manipulation
//Time Complexity:O(1)
//Space Complexity:O(1)
if(n < 1){
return false;
}
return (n & (n-1)) == 0;
}
}
。
。
。
。
。
。
Two Pointers Python Code:
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def isPalindrome(self, head: ListNode) -> bool:
#Two Pointers
#N is the size of nums
#Time Complexity:O(N)
#Space Complexity:O(N)
if head is None or head.next is None:
return True
arr = []
while(head is not None):
arr.append(head.val)
head = head.next
l, r = 0, len(arr)-1
while(l<r):
if(arr[l] != arr[r]):
return False
l += 1
r -= 1
return True
Recursion Python Code:
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
p = ListNode()
def isPalindrome(self, head: ListNode) -> bool:
#Recursion
#N is the size of nums
#Time Complexity:O(N)
#Space Complexity:O(N)
self.p = head
return self.recursion(head)
def recursion(self,head):
if head is None: #此处head不能为[]?
return True
if not self.recursion(head.next):
return False #在此处一直迭代下去,直到没有迭代结束。开始返回。
if self.p.val != head.val:
return False
self.p = self.p.next
return True
Stack Python Code:
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def isPalindrome(self, head: ListNode) -> bool:
#Stack
#N is the size of list
#Time Complexity:O(N)
#Space Complexity:O(N)
if head is None and head.next is None:
return True
stack = []
temp = head
while temp is not None:
stack.append(temp.val)
temp = temp.next
while(len(stack)!=0 and head is not None):
if(stack.pop() != head.val):
return False
head = head.next
return True
Fast and Slow Pointer
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def isPalindrome(self, head: ListNode) -> bool:
#Fast and Slow pointer
#N is the size of list
#Time Complexity:O(N)
#Space Complexity:O(1)
if head is None or head.next is None:
return True
slow = head
fast = head
#find the half point of the head
while fast is not None and fast.next is not None:
#Move one step per time
slow = slow.next
#Move two steps per time
fast = fast.next.next
if fast is not None:
slow = slow.next
fast = head
#Reverse second half list
reversedList = self.reversedList(slow)
while(reversedList is not None):
if fast.val != reversedList.val:
return False
fast = fast.next
reversedList = reversedList.next
return True
def reversedList(self,head):
current = head
previous = None
while current is not None:
next_node = current.next
current.next = previous
previous = current
current = next_node
return previous
Two Pointers JAVA Code:
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
class Solution {
public boolean isPalindrome(ListNode head) {
//Two Pointers
//N is the size of list
//Time Complexity:O(N)
//Space Complexity:O(N)
if(head == null || head.next == null){
return true;
}
ArrayList<Integer> list = new ArrayList<>();
while(head != null){
list.add(head.val);
head = head.next;
}
int l = 0;
int r = list.size() - 1;
while( l < r ){
//Integer cannot use ==,have to use equals
if(!list.get(l).equals(list.get(r))){
return false;
}
l++;
r--;
}
return true;
}
}
Recursion JAVA Code:
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
class Solution {
ListNode p = new ListNode();
public boolean isPalindrome(ListNode head) {
//Recursion
//N is the size of list
//Time Complexity:O(N)
//Space Complexity:O(N)
p = head;
return recursion(head);
}
private boolean recursion(ListNode head){
if(head == null){
return true;
}
if(!recursion(head.next)){
return false;
}
if(p.val != head.val){
return false;
}
p = p.next;
return true;
}
}
Stack JAVA Code:
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
class Solution {
public boolean isPalindrome(ListNode head) {
//Stack
//N is the size of list
//Time Complexity:O(N)
//Space Complexity:O(N)
if(head == null || head.next == null){
return true;
}
ListNode temp = head;
Stack<Integer> stack = new Stack<>();
while(temp != null){
stack.push(temp.val);
temp = temp.next;
}
while(head != null && ! stack.isEmpty()){
if(head.val != stack.pop()){
return false;
}
head = head.next;
}
return true;
}
}
Slow and Fast Pointer java Code:
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
class Solution {
public boolean isPalindrome(ListNode head) {
//Fast and Slow Pointer
//N is the size of list
//Time Complexity:O(N)
//Space Complexity:O(N)
if(head == null || head.next == null){
return true;
}
ListNode slow = head;
ListNode fast = head;
while(fast != null && fast.next != null){
slow = slow.next;
fast = fast.next.next;
}
if(fast != null){
slow = slow.next;
}
fast = head;
ListNode reversedList = reversedList(slow);
while(reversedList != null){
if(fast.val != reversedList.val){
return false;
}
fast = fast.next;
reversedList = reversedList.next;
}
return true;
}
private ListNode reversedList(ListNode head){
ListNode previous = null;
ListNode current = head;
while(current != null){
ListNode next = current.next;
current.next = previous;
previous = current;
current = next;
}
return previous;
}
}
264、丑数2 Ugly number 2
最小堆法、动态规划法
Min Heap + Hashset Python Code:
class Solution:
def nthUglyNumber(self, n: int) -> int:
#Min Heap + Hashset
#N is n
#Time Complexity:O(NlogN)
#Space Complexity:O(N)
hashset = set()
heap = []
hashset.add(1)
heapq.heappush(heap,1) #往堆中插入一条新的值
res = 1
factors = (2,3,5)
for i in range(0,n):
res = heapq.heappop(heap) #从堆中弹出最小值
for factor in factors:
newNum = res * factor
if newNum not in hashset: #排除重复的值
hashset.add(newNum)
heapq.heappush(heap,newNum)
return res
Min Heap + Hashset
class Solution {
public int nthUglyNumber(int n) {
//Min Heap + Hashset
//N is n
//Time Complexuty:O(NlogN)
//Space Complexity:O(N)
HashSet<Long> set = new HashSet<>();
PriorityQueue<Long> pq = new PriorityQueue<>();
set.add(1L);
pq.add(1L);
int res = 1;
long[] factors = {2L,3L,5L};
for(int i = 0;i < n; i++){
long uglyNum = pq.poll();
res = (int) uglyNum;
for(long factor:factors){
long newNum = uglyNum * factor;
if(!set.contains(newNum)){
set.add(newNum);
pq.add(newNum);
}
}
}
return res;
}
}
Dynamic Programming Python Code:
class Solution:
def nthUglyNumber(self, n: int) -> int:
#Dynamic Programming
#N is n
#Time Complxity:O(N)
#Space Complexity:(N)
dp = [0] * (n + 1)
dp[1] = 1
p2 = 1
p3 = 1
p5 = 1
for i in range(2,n+1):
t2 = dp[p2] * 2
t3 = dp[p3] * 3
t5 = dp[p5] * 5
dp[i] = min(t2,t3,t5)
if t2 == dp[i]:
p2 += 1
if t3 == dp[i]:
p3 += 1
if t5 == dp[i]:
p5 += 1
return dp[n]
Dynamic Programming JAVA Code:
class Solution {
public int nthUglyNumber(int n) {
//Dynamic Programming
//N is n
//Time Complexity:O(N)
//Space Complexity:O(N)
int[] dp = new int[n+1];
dp[1] = 1;
int p2 = 1;
int p3 = 1;
int p5 = 1;
for(int i = 2; i <= n; i++){
int t2 = dp[p2] * 2;
int t3 = dp[p3] * 3;
int t5 = dp[p5] * 5;
dp[i] = Math.min(t2,Math.min(t3,t5));
if(t2 == dp[i]){
p2++;
}
if(t3 == dp[i]){
p3++;
}
if(t5 == dp[i]){
p5++;
}
}
return dp[n];
}
}