目录
栈先进后出的特性;二叉数遍历递归和栈两种实现。stack:push,pop;queue:add(),poll();priorityQueue:add,remove,peek;二叉树的层序遍历:queue加count
leetcode20-有效的括号
给定一个只包括 '(',')','{','}','[',']' 的字符串,判断字符串是否有效。
有效字符串需满足:
左括号必须用相同类型的右括号闭合。
左括号必须以正确的顺序闭合。
注意空字符串可被认为是有效字符串。
思路:遇到左括号存入栈中,遇到右括号将栈中的第一个括号弹出进行匹配。
public boolean isValid(String s){
if(s.length()==0){
return true;
}
Stack<Character> stack = new Stack<>();
//遍历s
for(int i=0;i<s.length();i++){
if(s.charAt(i)=='['||s.charAt(i)=='('||s.charAt(i)=='{'){
stack.push(s.charAt(i));
}else{
if(stack.isEmpty()){
return false;
}else{
char c = stack.pop();
if(s.charAt(i)==']'&&c=='['){
continue;
}else if(s.charAt(i)==')'&&c=='('){
continue;
}else if(s.charAt(i)=='}'&&c=='{'){
continue;
}else{
return false;
}
}
}
}
return stack.isEmpty();
}
leetcode144-二叉树的前序遍历
给定一个二叉树,返回它的 前序 遍历。
示例:
输入: [1,null,2,3]
1
\
2
/
3
输出: [1,2,3]
思路:前序遍历:根节点->左子树->右子树。使用递归算法,依次将节点加入结果res中
//使用递归算法
public List<Integer> preorderTraversal(TreeNode root){
List<Integer> res = new ArrayList<>();
preOrder(root,res);
return res;
}
private void preOrder(TreeNode node,List<Integer> res){
if(node == null){
return;
}
res.add(node.val);
preOrder(node.left,res);
preOrder(node.right,res);
}
思路2:使用栈来进行遍历.将要处理的节点依次压入栈,再依次将节点取出,把值存入res,将其right和left压入栈,注意先right后left,先进后出,才能先处理left。
//使用栈来遍历,依次将需要操作的数压入栈中
public List<Integer> preorderTraversal(TreeNode root){
List<Integer> res = new ArrayList<>();
if(root==null){
return res;
}
Stack<TreeNode> stack = new Stack<>();
stack.push(root);
while(!stack.isEmpty()){
TreeNode temp = stack.pop();
// System.out.print(temp.val);
res.add(temp.val);
if(temp.right!=null){
stack.push(temp.right);
}
if(temp.left!=null){
stack.push(temp.left);
}
}
return res;
}
leetcode102-二叉树的层次遍历
给定一个二叉树,返回其按层次遍历的节点值。 (即逐层地,从左到右访问所有节点)。
例如:
给定二叉树: [3,9,20,null,null,15,7],
3
/ \
9 20
/ \
15 7
返回其层次遍历结果:
[
[3],
[9,20],
[15,7]
]
思路:将每一层要处理的节点放入queue中,记录每一层的节点数,当节点数为0时,进入下一次层。queue加入add 弹出poll
//使用队列,将每一层的节点加入queue中,记录每一层的queue的节点数量,处理完后数量为0说明到了下一层。
public List<List<Integer>> levelOrder(TreeNode root){
List<List<Integer>> res = new ArrayList<>();
if(root==null){
return res;
}
Queue<TreeNode> queue = new LinkedList<>();
queue.add(root);
while(!queue.isEmpty()){
int count = queue.size();
List<Integer> list = new ArrayList<Integer>();
while(count>0){
TreeNode temp = queue.poll();
list.add(temp.val);
if(temp.left!=null){
queue.add(temp.left);
}
if(temp.right!=null){
queue.add(temp.right);
}
count--;
}
res.add(list);
}
return res;
}
leetcode279-完全平法数
给定正整数 n,找到若干个完全平方数(比如 1, 4, 9, 16, ...)使得它们的和等于 n。你需要让组成和的完全平方数的个数最少。
示例 1:
输入: n = 12
输出: 3
解释: 12 = 4 + 4 + 4.
示例 2:
输入: n = 13
输出: 2
解释: 13 = 4 + 9.
思路:将num-i*i的所有可能结果放入queue中,再从queue中取出num重复以上操作,当最先有num=0时,存在最短步数。
public int numSquares(int n) {
if(n==0){
return 0;
}
Queue<Integer> queue = new LinkedList<Integer>();
queue.add(n);
boolean[] visited = new boolean[n+1];
visited[n] = true;
int step = 0;
while(!queue.isEmpty()){
int count = queue.size();
while(count>0){
int num = queue.poll();
if(num==0){
return step;
}else{
for(int i=0;i*i<=num;i++){
if(visited[num-i*i]==false){
queue.add(num-i*i);
visited[num-i*i]=true;
}
}
}
count--;
}
step++;
}
return step;
}
leetcode347-前k个高频元素
给定一个非空的整数数组,返回其中出现频率前 k 高的元素。
示例 1:
输入: nums = [1,1,1,2,2,3], k = 2
输出: [1,2]
示例 2:
输入: nums = [1], k = 1
输出: [1]
说明:
你可以假设给定的 k 总是合理的,且 1 ≤ k ≤ 数组中不相同的元素的个数。
你的算法的时间复杂度必须优于 O(n log n) , n 是数组的大小。
思路:使用优先队列存放前k个高频元素,优先队列的优先级由其出现的频率决定。
public List<Integer> topKFrequent(int[] nums, int k){
List<Integer> res = new ArrayList<>();
if(nums.length==0){
return res;
}
//将每个元素出现的次数存入map中
Map<Integer,Integer> map = new HashMap<>();
for(int i=0;i<nums.length;i++){
if(map.get(nums[i])==null){
map.put(nums[i],1);
}else{
map.put(nums[i],map.get(nums[i])+1);
}
}
//使用一个优先队列来存储频率前k高的元素,传入conparator
PriorityQueue<Integer> queue = new PriorityQueue<>(new Comparator<Integer>(){
@Override
public int compare(Integer o1,Integer o2){
return map.get(o1)-map.get(o2);
}
});
//queue中只存放k个元素,遍历map将值放入queue中
for(Integer key:map.keySet()){
if(queue.size()<k){
queue.add(key);
}else if(map.get(key)>map.get(queue.peek())){
queue.remove();
queue.add(key);
}
}
//将queue的值存入res中
while(!queue.isEmpty()){
res.add(queue.remove());
}
return res;
}
习题
leetcode150-逆波兰表达式求值
根据逆波兰表示法,求表达式的值。
有效的运算符包括 +, -, *, / 。每个运算对象可以是整数,也可以是另一个逆波兰表达式。
说明:
整数除法只保留整数部分。
给定逆波兰表达式总是有效的。换句话说,表达式总会得出有效数值且不存在除数为 0 的情况。
示例 1:
输入: ["2", "1", "+", "3", "*"]
输出: 9
解释: ((2 + 1) * 3) = 9
示例 2:
输入: ["4", "13", "5", "/", "+"]
输出: 6
解释: (4 + (13 / 5)) = 6
示例 3:
输入: ["10", "6", "9", "3", "+", "-11", "*", "/", "*", "17", "+", "5", "+"]
输出: 22
解释:
((10 * (6 / ((9 + 3) * -11))) + 17) + 5
= ((10 * (6 / (12 * -11))) + 17) + 5
= ((10 * (6 / -132)) + 17) + 5
= ((10 * 0) + 17) + 5
= (0 + 17) + 5
= 17 + 5
= 22
思路:将非运算符压入栈中,当遇到运算符时,取出栈中的两个数据进行运算,并将运算结果压入栈。注意String和int类型转换。int b = Integer.parseInt(stack.pop());String.valueOf(a+b)
public int evalRPN(String[] tokens) {
//将数字存入一个栈,当遇到算术运算符,就弹出栈中的两个数进行运算,再将结果压入栈中
Stack<String> stack = new Stack<>();
for(int i=0;i<tokens.length;i++){
if(!"+".equals(tokens[i])&&!"-".equals(tokens[i])&&!"*".equals(tokens[i])&&!"/".equals(tokens[i])){
stack.push(tokens[i]);
}else{
int b = Integer.parseInt(stack.pop());
int a = Integer.parseInt(stack.pop());
if("+".equals(tokens[i])){
stack.push(String.valueOf(a+b));
}
if("-".equals(tokens[i])){
stack.push(String.valueOf(a-b));
}
if("*".equals(tokens[i])){
stack.push(String.valueOf(a*b));
}
if("/".equals(tokens[i])){
stack.push(String.valueOf(a/b));
}
}
}
return Integer.parseInt(stack.pop());
}
leetcode94-二叉树的中序遍历
给定一个二叉树,返回它的中序 遍历。
示例:
输入: [1,null,2,3]
1
\
2
/
3
输出: [1,3,2]
进阶: 递归算法很简单,你可以通过迭代算法完成吗?
思路:递归实现
//递归实现
public List<Integer> inorderTraversal(TreeNode root) {
List<Integer> res = new ArrayList<>();
if(root==null){
return res;
}
inOrder(root,res);
return res;
}
public void inOrder(TreeNode node,List<Integer> res){
if(node==null){
return;
}
if(node.left!=null){
inOrder(node.left,res);
}
res.add(node.val);
if(node.right!=null){
inOrder(node.right,res);
}
}
思路2:非递归实现,先将左右左边的元素压入栈,再依次弹出,再将右边的元素压入栈,依次弹出
//非递归实现,使用栈
public static List<Integer> inorderTraversal(TreeNode root){
List<Integer> res = new ArrayList<>();
if(root==null){
return res;
}
Stack<TreeNode> stack = new Stack<>();
TreeNode cur = root;
while(!stack.isEmpty()||cur!=null){
while (cur!=null){
stack.push(cur);
cur = cur.left;
}
cur = stack.pop();
res.add(cur.val);
cur = cur.right;
}
return res;
}
leetcode145-二叉树的后序遍历
给定一个二叉树,返回它的 后序 遍历。
示例:
输入: [1,null,2,3]
1
\
2
/
3
输出: [3,2,1]
进阶: 递归算法很简单,你可以通过迭代算法完成吗?。
思路:递归实现
//递归实现
public List<Integer> postorderTraversal(TreeNode root) {
List<Integer> res = new ArrayList<>();
if(root==null){
return res;
}
postOrder(root,res);
return res;
}
private void postOrder(TreeNode node,List<Integer> res){
if(node==null){
return;
}
if(node.left!=null){
postOrder(node.left,res);
}
if(node.right!=null){
postOrder(node.right,res);
}
res.add(node.val);
}
思路2:二叉树的前序遍历大家都会写吧,很简单,顺序是中左右。而二叉树的后序遍历顺序是左右中。于是可以把前序遍历左右调换一下,变成中右左,最后再整体reverse一下,不就变成左右中了
public List<Integer> postorderTraversal1(TreeNode root) {
List<Integer> res = new ArrayList<>();
if(root == null) return res;
Stack<TreeNode> stack = new Stack<>();
stack.push(root);
while(!stack.isEmpty()){
TreeNode cur = stack.pop();
res.add(cur.val);
if(cur.left != null){
stack.push(cur.left);
}
if(cur.right != null){
stack.push(cur.right);
}
}
Collections.reverse(res);
return res;
}
leetcode341-扁平化嵌套列表迭代器
public class NestedIterator implements Iterator<Integer> {
private int current = 0;
private List<NestedInteger> nestedList;
private NestedIterator it;
public NestedIterator(List<NestedInteger> nestedList) {
this.nestedList = nestedList;
}
@Override
public Integer next() {
if(it != null) {
if(it.hasNext()){
return it.next();
}else{
current++;
it = null;
}
}
NestedInteger integer = nestedList.get(current);
if(integer.isInteger()) {
current++;
it = null;
return integer.getInteger();
}else{
it = new NestedIterator(integer.getList());
return next();
}
}
@Override
public boolean hasNext() {
if(it != null) {
if(it.hasNext())
return true;
current++;
it = null;
}
if(current >= nestedList.size())
return false;
NestedInteger integer = nestedList.get(current);
if(integer.isInteger()) {
return true;
}else{
it = new NestedIterator(integer.getList());
return hasNext();
}
}
}
leetcode107-二叉树的层次遍历
给定一个二叉树,返回其节点值自底向上的层次遍历。 (即按从叶子节点所在层到根节点所在的层,逐层从左向右遍历)
例如:
给定二叉树 [3,9,20,null,null,15,7],
3
/ \
9 20
/ \
15 7
返回其自底向上的层次遍历为:
[
[15,7],
[9,20],
[3]
]
思路:使用Queue来存放要遍历的节点,count来控制每一层的数量。从叶子节点向根节点遍历,先用stack存储结果List,再将每个Listpop()存入最终结果中
public List<List<Integer>> levelOrderBottom(TreeNode root) {
List<List<Integer>> res = new ArrayList<>();
if(root==null){
return res;
}
//先将结果存放在栈中
Stack<List<Integer>> stack = new Stack<>();
Queue<TreeNode> nodes = new LinkedList<>();
nodes.add(root);
while(nodes.size()!=0){
int count = nodes.size();
System.out.println(count+" 1");
List<Integer> list = new ArrayList<>();
while(count>0){
TreeNode temp = nodes.poll();
list.add(temp.val);
System.out.println(temp.val+" 2");
if(temp.left!=null){
System.out.println(temp.left.val+" 3");
nodes.add(temp.left);
}
if(temp.right!=null){
System.out.println(temp.right.val+" 4");
nodes.add(temp.right);
}
count--;
}
stack.push(list);
}
//将stack中的数据取出来依次放入结果中
while(!stack.isEmpty()){
res.add(stack.pop());
}
return res;
}
leetcode103-二叉树锯齿形层次遍历
给定一个二叉树,返回其节点值的锯齿形层次遍历。(即先从左往右,再从右往左进行下一层遍历,以此类推,层与层之间交替进行)。
例如:
给定二叉树 [3,9,20,null,null,15,7],
3
/ \
9 20
/ \
15 7
返回锯齿形层次遍历如下:
[
[3],
[20,9],
[15,7]
]
思路:还是使用queue进行层次遍历,但是在将每一层的结果存入结果res中时,判断层数step。若为奇数层,直接加入,若为偶数层倒序再加入。奇数层的处理是在加入数据时先放入一个栈中,再依次弹出加入到list中。
public List<List<Integer>> zigzagLevelOrder(TreeNode root){
List<List<Integer>> res = new ArrayList<>();
if(root==null){
return res;
}
Queue<TreeNode> queue = new LinkedList<>();
int step = 0;
queue.add(root);
while(queue.size()!=0){
int count = queue.size();
List<Integer> list = new ArrayList<>();
Stack<Integer> stack = new Stack<>();
while(count>0){
TreeNode node = queue.poll();
if(step%2==0){
list.add(node.val);
}else{
stack.push(node.val);
}
if(node.left!=null){
System.out.println(node.left.val+" 3");
queue.add(node.left);
}
if(node.right!=null){
System.out.println(node.right.val+" 4");
queue.add(node.right);
}
count--;
}
if(step%2==0){
res.add(list);
}else{
List<Integer> temp = new ArrayList<>();
while(!stack.isEmpty()){
temp.add(stack.pop());
}
res.add(temp);
}
step++;
}
return res;
}
leetcode199-二叉树的右视图
给定一棵二叉树,想象自己站在它的右侧,按照从顶部到底部的顺序,返回从右侧所能看到的节点值。
示例:
输入: [1,2,3,null,5,null,4]
输出: [1, 3, 4]
解释:
1 <---
/ \
2 3 <---
\ \
5 4 <---
思路:还是用层序遍历方法queue加count,只是在count==1的时候,将当前节点的值加入res中。
public List<Integer> rightSideView(TreeNode root) {
List<Integer> res = new ArrayList<>();
if(root==null){
return res;
}
Queue<TreeNode> queue = new LinkedList<>();
queue.add(root);
while(queue.size()!=0){
int count = queue.size();
while(count>0){
TreeNode node = queue.poll();
if(count==1){
res.add(node.val);
}
if(node.left!=null){
queue.add(node.left);
}
if(node.right!=null){
queue.add(node.right);
}
count--;
}
}
return res;
}