26.重排链表
package com.lxh.list;
/**
* @Author: Tiger
* @Description: 面试题26:重排链表
* 1. 对链表的做题中要注意反转链表这种解题思路
* @Date: 下午 19:46 2021/11/3 0003
**/
public class RearrangedList26 {
public void reorderList(ListNode head) {
ListNode dummy = new ListNode(0);
dummy.next = head;
ListNode fast = dummy;
ListNode slow = dummy;
//找到中间节点
while (fast != null && fast.next != null) {
slow = slow.next;
fast = fast.next;
if (fast.next != null)
fast = fast.next;
}
ListNode temp = slow.next;
slow.next = null;
link(head, reverseList(temp),dummy);
}
//反转链表
private ListNode reverseList(ListNode head) {
ListNode cur = head;
ListNode prev = null;
ListNode next = null;
while (cur != null) {
next = cur.next;
cur.next = prev;
prev = cur;
cur = next;
}
return prev;
}
//穿针引线
private void link(ListNode node1, ListNode node2, ListNode head) {
ListNode prev = head;
while (node1 != null && node2 != null) {
ListNode temp = node1.next;
prev.next = node1;
node1.next = node2;
prev = node2;
node1 = temp;
node2 = node2.next;
}
if (node1 != null)
prev.next = node1;
}
}
27.回文链表
package com.lxh.list;
/**
* @Author: Tiger
* @Description: 回文链表
* @Date: 下午 20:58 2021/11/3 0003
**/
public class PalindromeList27 {
public boolean isPalindrome(ListNode head) {
if (head == null || head.next == null)
return true;
ListNode slow = head;
ListNode fast = head.next;
while (fast.next != null && fast.next.next != null) {
fast = fast.next.next;
slow = slow.next;
}
ListNode secondHalf = slow.next;
if (fast.next != null)
secondHalf = slow.next.next;
//这句话一加,head所代表的链表就到slow后面的null了
slow.next = null;
return equals(secondHalf, reverseList(head));
}
private ListNode reverseList(ListNode head) {
ListNode cur = head;
ListNode prev = null;
ListNode next = null;
while (cur != null) {
next = cur.next;
cur.next = prev;
prev = cur;
cur = next;
}
return prev;
}
private boolean equals(ListNode head1, ListNode head2) {
while (head1 != null && head2 != null) {
if (head1.val != head2.val)
return false;
head1 = head1.next;
head2 = head2.next;
}
return head1 == null && head2 == null;
}
}
28.展平多级双向链表
package com.lxh.list;
/**
* @Author: Tiger
* @Description: 展平多级双向链表
* @Date: 下午 16:00 2021/11/4 0004
**/
public class FlatteningDoublyLinkedLists28 {
public Node flatten(Node head) {
flattenGetTail(head);
return head;
}
private Node flattenGetTail(Node head) {
Node node = head;
Node tail = null;
while (node != null) {
Node next = node.next;
if (node.child != null) {
Node child = node.child;
Node childTail = flattenGetTail(node.child);
node.child = null;
node.next = child;
child.prev = node;
childTail.next = next;
if (next != null) {
next.prev = childTail;
}
tail = childTail;
}else
tail = node;
node = next;
}
return tail;
}
}
29.排序的循环链表
package com.lxh.list;
/**
* @Author: Tiger
* @Description: 面试题29:排序的循环链表
* @Date: 下午 16:32 2021/11/4 0004
**/
public class SortedCircularList29 {
public Node insert(Node head, int insertVal) {
Node node = new Node(insertVal);
if (head == null) {
head = node;
head.next = head;
}else if (head.next == head) {
head.next = node;
node.next = head;
}else {
insertCore(head, node);
}
return head;
}
private void insertCore(Node head, Node node) {
Node cur = head;
Node next = head.next;
Node biggest = head;
while (!(cur.val <= node.val && next.val >= node.val) && next != head) {
cur = next;
next = next.next;
if (cur.val >= biggest.val)
biggest = cur;
}
if (cur.val <= node.val && next.val >= node.val) {
cur.next = node;
node.next = next;
}else {
node.next = biggest.next;
biggest.next = node;
}
}
}
30.插入、删除和随机访问都是O(1)的容器
package com.lxh.hash;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Random;
/**
* @Author: Tiger
* @Description: 面试题30:插入、删除和随机访问都是O(1)的容器
* 1. 思想很重要 同时学习取随机数函数
* @Date: 下午 19:55 2021/11/4 0004
**/
class RandomContainer30 {
HashMap<Integer, Integer> numToLocation;
ArrayList<Integer> nums;
//预处理
public RandomContainer30() {
numToLocation = new HashMap<>();
nums = new ArrayList<>();
}
//如果数据集中不包含一个数值,则把它添加到数据集中
public boolean insert(int val) {
if (numToLocation.containsKey(val))
return false;
//哈希表中存储当前值和在数组中的位置(数组下标)
numToLocation.put(val, nums.size());
nums.add(val);
return true;
}
//如果数据集中包含一个数值,则把它删除
public boolean remove(int val) {
if (!numToLocation.containsKey(val))
return false;
int location = numToLocation.get(val);
//注意数组长度和数组下标之间的关系
numToLocation.put(nums.get(nums.size() - 1), location);
numToLocation.remove(val);
nums.set(location, nums.get(nums.size() - 1));
nums.remove(nums.size() - 1);
return true;
}
//随机访问,随机返回数据集中的一个数值,要求数据集中每个数字都被返回的概率都相同
//取随机数函数
public int getRandom() {
Random random = new Random();
int r = random.nextInt(nums.size());
return nums.get(r);
}
}
31.最近最少使用缓存 (again)
package com.lxh.hash;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @Author: Tiger
* @Description: 面试题31:最近最少使用缓存 (again)
* @Date: 下午 22:04 2021/11/6 0006
**/
class ListNode {
public int key;
public int value;
public ListNode next;
public ListNode prev;
public ListNode(int k, int v) {
key = k;
value = v;
}
}
class LeastRecentlyUsedCache31 {
private ListNode head;
private ListNode tail;
private Map<Integer, ListNode> map;
int capacity;
public LeastRecentlyUsedCache31(int cap) {
map = new HashMap<>();
//创建一头一尾两个哨兵节点,put所添加的节点位于这两个节点之间
head = new ListNode(-1, -1);
tail = new ListNode(-1, -1);
head.next = tail;
tail.prev = head;
capacity = cap;
}
public int get(int key) {
ListNode node = map.get(key);
if (node == null) {
return -1;
}
moveToTail(node, node.value);
return node.value;
}
public void put(int key, int value) {
if (map.containsKey(key)) {
moveToTail(map.get(key), value);
}else {
if (map.size() == capacity) {
ListNode toBeDeleted = head.next;
deleteNode(toBeDeleted);
map.remove(toBeDeleted.key);
}
ListNode node = new ListNode(key, value);
insertToTail(node);
map.put(key, node);
}
}
//把双向链表中的一个节点移到链表的尾部
private void moveToTail(ListNode node, int newValue) {
deleteNode(node);
node.value = newValue;
insertToTail(node);
}
private void deleteNode(ListNode node) {
node.prev.next = node.next;
node.next.prev = node.prev;
}
private void insertToTail(ListNode node) {
tail.prev.next = node;
node.prev = tail.prev;
node.next = tail;
tail.prev = node;
}
}
32.有效的变位词
package com.lxh.hash;
import java.util.HashMap;
import java.util.Map;
/**
* @Author: Tiger
* @Description: 面试题32:有效的变位词
* @Date: 下午 17:43 2021/11/7 0007
**/
/*如果只考虑英文字母,则用数组来模拟哈希表
public class ValidConjugation32 {
public boolean isAnagram(String str1, String str2) {
if (str1.length() != str2.length())
return false;
int[] counts = new int[26];
for (char ch : str1.toCharArray()) {
counts[ch - 'a']++;
}
for (char ch : str2.toCharArray()) {
if (counts[ch - 'a'] == 0)
return false;
counts[ch - 'a']--;
}
return true;
}
}*/
//考虑非英文字母,则用真正的哈希表HashMap
public class ValidConjugation32 {
public boolean isAnagram(String str1, String str2) {
if (str1.length() != str2.length())
return false;
Map<Character, Integer> counts = new HashMap<>();
for (char ch : str1.toCharArray()) {
counts.put(ch, counts.getOrDefault(ch, 0) + 1);
}
for (char ch : str2.toCharArray()) {
if (!counts.containsKey(ch) || counts.get(ch) == 0) {
return false;
}
counts.put(ch, counts.get(ch) - 1);
}
return true;
}
}
33.变位词组
package com.lxh.hash;
import java.util.*;
/**
* @Author: Tiger
* @Description: 面试题33:变位词组
* @Date: 下午 18:08 2021/11/7 0007
**/
/*将单词映射到数字 该算法的时间复杂度为O(mn)但该解法有个问题 可能会造成溢出
public class ConjugationPhrase33 {
public List<List<String>> groupAnagrams(String[] strs) {
int hash[] = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101};
Map<Long, List<String>> groups = new HashMap<>();
for (String str : strs) {
long wordHash = 1;
for (int i = 0; i < str.length(); ++i) {
wordHash *= hash[str.charAt(i) - 'a'];
}
//使用putIfAbsent方法添加键值对,如果map集合中没有该key对应的值,则直接添加,并返回null,如果已经存在对应的值,则依旧为原来的值。
//此处当数字乘积没有出现过则创建一个新的以key为首的链表,当存在时则保持原来的链表
groups.putIfAbsent(wordHash, new LinkedList<String>());
groups.get(wordHash).add(str);
}
//groups.value()本身就是一个链表了
return new LinkedList<>(groups.values());
}
}*/
//
public class ConjugationPhrase33 {
public List<List<String>> groupAnagrams(String[] strs) {
Map<String, List<String>> groups = new HashMap<>();
for (String str : strs) {
//将字符串转换成字符数组
char[] charArray = str.toCharArray();
Arrays.sort(charArray);
//将排完序的字符数组再转回字符串
String sorted = new String(charArray);
groups.putIfAbsent(sorted, new LinkedList<String>());
//因为获得的值为一个链表 所以可以直接利用链表的add进行添加
groups.get(sorted).add(str);
}
//哈希表有keys和values可以直接调用
return new LinkedList<>(groups.values());
}
}
34.外星语言是否排序
package com.lxh.hash;
/**
* @Author: Tiger
* @Description: 面试题34:外星语言是否排序
* 1. 时间复杂度为O(mn) 空间复杂度为O(1)
* @Date: 下午 18:52 2021/11/7 0007
**/
public class AreAlienLanguagesSorted34 {
public boolean isAlienSorted(String[] words, String order) {
int[] orderArray = new int[order.length()];
//先出现的字符的值越小
for (int i = 0; i < order.length() - 1; ++i) {
orderArray[order.charAt(i) - 'a'] = i;
}
for (int i = 0; i < words.length - 1; ++i) {
if (!isSorted(words[i], words[i + 1], orderArray))
return false;
}
return true;
}
private boolean isSorted(String word1, String word2, int[] order) {
int i = 0;
for (; i < word1.length() && i < word2.length(); ++i) {
char ch1 = word1.charAt(i);
char ch2 = word2.charAt(i);
if (order[ch1 - 'a'] < order[ch2 - 'a']) {
return true;
}
if (order[ch1 - 'a'] > order[ch2 - 'a']) {
return false;
}
}
//当不一样长时,说明word2字符串长度更短,应该排在word1前面
return i == word1.length();
}
}
35.最小时间差
package com.lxh.hash;
import java.util.List;
import java.util.Map;
/**
* @Author: Tiger
* @Description: 面试题35:最小时间差
* @Date: 下午 19:20 2021/11/7 0007
**/
public class MinimumTimeDifference35 {
public int findMinDifference(List<String> timePoints) {
if (timePoints.size() > 1440) {
return 0;
}
boolean minuteFlags[] = new boolean[1440];
for (String time : timePoints) {
//spilt函数将字符串按照某一个指定符号进行分割开并形成字符串数组
String t[] = time.split(":");
//Integer.parseInt(“”)返回的是一个基本类型的int,将字符串直接转换为数字
//将时间变成以分钟来表示的
int min = Integer.parseInt(t[0]) * 60 + Integer.parseInt(t[1]);
//说明此时已经存在同时间点 故最小时间差为0
if (minuteFlags[min])
return 0;
minuteFlags[min] = true;
}
return helper(minuteFlags);
}
//
private int helper(boolean minuteFlags[]) {
int minDiff = minuteFlags.length - 1;
int prev = -1;
int first = minuteFlags.length - 1;
int last = -1;
for (int i = 0; i < minuteFlags.length; ++i) {
if (minuteFlags[i]) {
if (prev >= 0 )
minDiff = Math.min(i - prev, minDiff);
prev = i;
//first用来记录最小的时间位置
first = Math.min(i, first);
//last用来记录最大的时间位置
last = Math.max(i, last);
}
}
//要将最小的时间加上一天1440分钟作为第二天时间与最长的时间位置进行比较
minDiff = Math.min(first + minuteFlags.length - last, minDiff);
return minDiff;
}
}
36.后缀表达式
package com.lxh.stack;
import java.util.Stack;
/**
* @Author: Tiger
* @Description: 面试题36:后缀表达式
* 1. 时间复杂度O(n) 空间复杂度O(n)
* @Date: 下午 21:02 2021/11/8 0008
**/
public class PostfixExpression36 {
public int evalRPN(String[] tokens) {
Stack<Integer> stack = new Stack<Integer>();
for (String token : tokens) {
switch (token) {
case "+":
case "-":
case "*":
case "/":
int num1 = stack.pop();
int num2 = stack.pop();
//先出来的为右操作数
stack.push(calculate(num2, num1, token));
break;
default:
//将字符串转换为整数
stack.push(Integer.parseInt(token));
}
}
return stack.pop();
}
private int calculate(int num1, int num2, String operator) {
switch (operator) {
case "+":
return num1 + num2;
case "-":
return num1 - num2;
case "*":
return num1 * num2;
case "/":
return num1 / num2;
default:
return 0;
}
}
}
37.小行星碰撞
package com.lxh.stack;
import java.lang.reflect.Array;
import java.util.Arrays;
import java.util.Stack;
/**
* @Author: Tiger
* @Description: 面试题37:小行星碰撞
* 1. 时间复杂度O(n) 空间复杂度O(n)
* 2. stack.stream().mapToInt(i->i).toArray();
* @Date: 上午 11:13 2021/11/9 0009
**/
public class AsteroidCollision37 {
public int[] asteroidCollision(int[] asteroids) {
Stack<Integer> stack = new Stack<>();
for (int as : asteroids) {
while (!stack.empty() && stack.peek() > 0 && stack.peek() < -as) {
stack.pop();
}
if (!stack.empty() && as < 0 && stack.peek() == -as) {
stack.pop();
}else if (as > 0 || stack.empty() || stack.peek() < 0) {
stack.push(as);
}
}
//mapToInt(i->i)它将每个 Integer 拆箱为一个 int
//将栈内数据转换为数组的方法
return stack.stream().mapToInt(i->i).toArray();
}
public static void main(String[] args) {
AsteroidCollision37 ac37 = new AsteroidCollision37();
int[] nums = {4, 5, -6, 4, 8, -5};
// nums = ac37.asteroidCollision(nums);
System.out.println(Arrays.toString(ac37.asteroidCollision(nums)));
}
}
38.每日温度
package com.lxh.stack;
import java.util.Stack;
/**
* @Author: Tiger
* @Description: 面试题38:每日温度
* @Date: 下午 14:12 2021/11/9 0009
**/
public class DailyTemperature38 {
public int[] dailyTemperatures(int[] temperatures) {
int[] result = new int[temperatures.length];
//用栈保存温度的数组下标
Stack<Integer> stack = new Stack<>();
for (int i = 0; i < temperatures.length; i++) {
while (!stack.empty() && temperatures[i] > temperatures[stack.peek()]) {
int prev = stack.pop();
result[prev] = i - prev;
}
stack.push(i);
}
return result;
}
}
39.直方图最大矩形面积
package com.lxh.stack;
import java.util.Stack;
/**
* @Author: Tiger
* @Description: 面试题39:直方图最大矩形面积
* @Date: 下午 14:37 2021/11/9 0009
**/
public class MaximumRectangleAreaHistogram39 {
/*方案一:蛮力法 时间O(n*n) 空间O(1)
public int largestRectangleArea(int[] heights) {
int maxArea = 0;
for (int i = 0; i < heights.length; i++) {
int min = heights[i];
for (int j = 0; j < heights.length; j++) {
min = Math.min(min, heights[j]);
int area = min * (j - i + 1);
maxArea = Math.max(maxArea, area);
}
}
return maxArea;
}*/
//方案二:分治法 时间 平均O(nlogn) 最坏O(n*n) 空间 平均O(logn) 最坏O(n)
/*public int largestRectangleArea(int[] heights) {
return helper(heights, 0, heights.length);
}
private int helper(int[] heights, int start, int end) {
if (start == end) {
return 0;
}
if (start + 1 == end) {
return heights[start];
}
int minIndex = start;
for (int i = start + 1; i < end; i++) {
if (heights[i] < heights[minIndex]) {
minIndex = i;
}
}
int area = (end - start) * heights[minIndex];
int left = helper(heights, start, minIndex);
int right = helper(heights, minIndex + 1, end);
area = Math.max(area, left);
return Math.max(area, right);
}*/
//方案三:单调栈法 时间O(n) 空间O(n)
public int largestRectangleArea(int[] heights) {
Stack<Integer> stack = new Stack<>();
stack.push(-1);
int maxArea = 0;
for (int i = 0; i < heights.length; i++) {
while (stack.peek() != -1 && heights[stack.peek()] >= heights[i]) {
int height = heights[stack.pop()];
int width = i - stack.peek() - 1;
maxArea = Math.max(maxArea, height * width);
}
stack.push(i);
}
while (stack.peek() != -1) {
int height = heights[stack.pop()];
int width = heights.length - stack.peek() - 1;
maxArea = Math.max(maxArea, height * width);
}
return maxArea;
}
}
40.矩阵中的最大矩形
package com.lxh.stack;
import java.util.Stack;
/**
* @Author: Tiger
* @Description: 面试题40:矩阵中的最大矩形
* 1. 时间O(mn) 空间O(n)
* @Date: 下午 15:37 2021/11/9 0009
**/
public class LargestRectangleInMatrix40 {
public int maximalRectangle(char[][] matrix) {
if (matrix.length == 0 || matrix[0].length == 0)
return 0;
int[] heights = new int[matrix[0].length];
int maxArea = 0;
for (char[] row : matrix) {
for (int i = 0; i < row.length; i++) {
if (row[i] == '0') {
heights[i] = 0;
}else {
heights[i]++;
}
}
maxArea = Math.max(maxArea, largestRectangleArea(heights));
}
return maxArea;
}
private int largestRectangleArea(int[] heights) {
Stack<Integer> stack = new Stack<>();
stack.push(-1);
int maxArea = 0;
for (int i = 0; i < heights.length; i++) {
while (stack.peek() != -1 && heights[stack.peek()] >= heights[i]) {
int height = heights[stack.pop()];
int width = i - stack.peek() - 1;
maxArea = Math.max(maxArea, height * width);
}
stack.push(i);
}
while (stack.peek() != -1) {
int height = heights[stack.pop()];
int width = heights.length - stack.peek() - 1;
maxArea = Math.max(maxArea, height * width);
}
return maxArea;
}
}
41.滑动窗口的平均值
package com.lxh.queue;
import java.util.LinkedList;
import java.util.Queue;
/**
* @Author: Tiger
* @Description: 面试题41:滑动窗口的平均值
* @Date: 下午 20:05 2021/11/12 0012
**/
class MovingAverage {
private Queue<Integer> nums;
private int capacity;
private int sum;
public MovingAverage(int size) {
nums = new LinkedList<>();
capacity = size;
}
public double next(int val) {
//
nums.offer(val);
sum += val;
if (nums.size() > capacity) {
sum -= nums.poll();
}
return (double) sum / nums.size();
}
}
42.最近请求次数
package com.lxh.queue;
import java.util.LinkedList;
import java.util.Queue;
/**
* @Author: Tiger
* @Description: 面试题42:最近请求次数
* @Date: 下午 20:14 2021/11/12 0012
**/
class RecentCounter {
private Queue<Integer> times;
private int windowSize;
public RecentCounter() {
times = new LinkedList<>();
windowSize = 3000;
}
public int ping(int t) {
times.offer(t);
while (times.peek() + windowSize < t) {
times.poll();
}
return times.size();
}
}
43.在完全二叉树中添加节点
package com.lxh.queue;
import sun.reflect.generics.tree.Tree;
import java.util.LinkedList;
import java.util.Queue;
/**
* @Author: Tiger
* @Description: 面试题43:在完全二叉树中添加节点
* 1. 类型CBTInserter的构造函数 时间复杂度是O(n) 函数insert的时间复杂度是O(1)
* @Date: 上午 11:38 2021/11/13 0013
**/
class InsertNodeIntoBinaryTree43 {
private Queue<TreeNode> queue;
private TreeNode root;
public InsertNodeIntoBinaryTree43(TreeNode root) {
this.root = root;//把参数值赋给成员变量,成员变量的值改变
queue = new LinkedList<>();
queue.offer(root);
while (queue.peek().left != null && queue.peek().right != null) {
TreeNode node = queue.poll();
queue.offer(node.left);
queue.offer(node.right);
}
}
public int insert(int v) {
TreeNode parent = queue.peek();
TreeNode node = new TreeNode(v);
if (parent.left == null) {
parent.left = node;
}else {
//如果节点右孩子也有了 所以此时对于这个节点它的左右孩子都有了 就不可能是被插入的对象了
//就可以把它给删除了 同时把他的左右孩子放进队列 继续遍历找到第一个没有节点左右孩子不满的
parent.right = node;
queue.poll();
queue.offer(parent.left);
queue.offer(parent.right);
}
return parent.val;
}
public TreeNode get_root() {
return this.root;
}
}
44.二叉树中每层的最大值
package com.lxh.queue;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;
/**
* @Author: Tiger
* @Description: 面试题44:二叉树中每层的最大值
* @Date: 下午 15:17 2021/11/13 0013
**/
public class MaximumValueOfEachLevel44 {
/* 方案一:用一个队列实现二叉树的广度优先搜索
public List<Integer> largestValues(TreeNode root) {
int current = 0;
int next = 0;
Queue<TreeNode> queue = new LinkedList<>();
if (root != null) {
queue.offer(root);
current = 1;
}
List<Integer> result = new LinkedList<>();
int max = Integer.MIN_VALUE;
while (!queue.isEmpty()) {
TreeNode node = queue.poll();
current--;
max = Math.max(max, node.val);
if (node.left != null) {
queue.offer(node.left);
next++;
}
if (node.right != null) {
queue.offer(node.right);
next++;
}
if (current == 0) {
result.add(max);
max = Integer.MIN_VALUE;
current = next;
next = 0;
}
}
return result;
}*/
//方案二 用两个队列实现二叉树的广度优先搜索
public List<Integer> largestValues(TreeNode root) {
Queue<TreeNode> queue1 = new LinkedList<>();
Queue<TreeNode> queue2 = new LinkedList<>();
if (root != null) {
queue1.offer(root);
}
List<Integer> result = new LinkedList<>();
int max = Integer.MIN_VALUE;
while (!queue1.isEmpty()) {
TreeNode node = queue1.poll();
max = Math.max(max, node.val);
if (node.left != null) {
queue2.offer(node.left);
}
if (node.right != null) {
queue2.offer(node.right);
}
if (queue1.isEmpty()) {
result.add(max);
max = Integer.MIN_VALUE;
queue1 = queue2;
//将queue2重新初始化为空
queue2 = new LinkedList<>();
}
}
return result;
}
}
45.二叉树最底层最左边的值
package com.lxh.queue;
import java.util.LinkedList;
import java.util.Queue;
/**
* @Author: Tiger
* @Description: 面试题45:二叉树最底层最左边的值
* @Date: 下午 15:35 2021/11/13 0013
**/
public class LeftmostValueOfTheLowestLevel45 {
public int findBottomLeftValue(TreeNode root) {
Queue<TreeNode> queue1 = new LinkedList<>();
Queue<TreeNode> queue2 = new LinkedList<>();
queue1.offer(root);
int bottomLeft = root.val;
while (!queue1.isEmpty()) {
TreeNode node = queue1.poll();
if (node.left != null) {
queue2.offer(node.left);
}
if (node.right != null) {
queue2.offer(node.right);
}
if (queue1.isEmpty()) {
queue1 = queue2;
queue2 = new LinkedList<>();
if (!queue1.isEmpty()) {
bottomLeft = queue1.peek().val;
}
}
}
return bottomLeft;
}
}
46.二叉树的右侧视图
package com.lxh.queue;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;
/**
* @Author: Tiger
* @Description: 面试题46:二叉树的右侧视图
* @Date: 下午 15:43 2021/11/13 0013
**/
public class RightSideViewOfBinaryTree46 {
public List<Integer> rightSideView(TreeNode root) {
List<Integer> view = new LinkedList<>();
if (root == null)
return view;
Queue<TreeNode> queue1 = new LinkedList<>();
Queue<TreeNode> queue2 = new LinkedList<>();
queue1.offer(root);
while (!queue1.isEmpty()) {
TreeNode node = queue1.poll();
if (node.left != null) {
queue2.offer(node.left);
}
if (node.right != null) {
queue2.offer(node.right);
}
if (queue1.isEmpty()) {
view.add(node.val);
queue1 = queue2;
queue2 = new LinkedList<>();
}
}
return view;
}
}
47.二叉树剪枝(基于后续遍历)
package com.lxh.tree;
/**
* @Author: Tiger
* @Description: 面试题47:二叉树剪枝(基于后续遍历)
* @Date: 下午 17:09 2021/11/15 0015
**/
public class BinaryTreePruning47 {
public TreeNode pruneTree(TreeNode root) {
if (root == null) {
return root;
}
root.left = pruneTree(root.left);
root.right = pruneTree(root.right);
if (root.left == null && root.right == null && root.val == 0) {
return null;
}
return root;
}
}
48.序列化和反序列化二叉树
package com.lxh.tree;
/**
* @Author: Tiger
* @Description: 面试题48:序列化和反序列化二叉树
* 1. 序列化 是将二叉树序列化成一个字符串 反序列化是指 还原成原来二叉树的算法
* 2. String.valueOf(root.val)将数字转化成字符串 Integer.valueOf(str)将字符串转化成数字
* @Date: 上午 10:57 2021/11/16 0016
**/
public class SerializationAndDeserialization48 {
//序列化树
public String serialize(TreeNode root) {
if (root == null) {
return "#";
}
String leftStr = serialize(root.left);
String rightStr = serialize(root.right);
return String.valueOf(root.val) + "," + leftStr + "," + rightStr;
}
//反序列化二叉树
/* 关于此处我们需要一个下标去扫描字符串数组nodeStrs中的每个字符串。通常用一个整数值来表示数组的下标,
* 但在下述代码中却定义了一个长度为1的整数数组i。这是因为递归函数dfs每反序列化一个节点时下标就会增加1,
* 并且函数的调用者需要知道下标增加了。如果函数dfs的第二个参数i是整数类型,那么即使在函数体内修改i的值,
* 修改之后的值也不能传递给它的调用者。但把i定义为整数数组之后,可以修改整数数组中的数字,修改之后的数值
* 就能传给他的调用者了。
*
* ?:为什么当定义一个整数类型时 在函数体内修改i的值 也不能传递给它的调用者。
* */
public TreeNode deserialize(String data) {
String[] nodeStrs = data.split(",");
int[] i = {0};
return dfs(nodeStrs, i);
}
private TreeNode dfs(String[] strs, int[] i) {
String str = strs[i[0]];
i[0]++;
if (str.equals("#")) {
return null;
}
TreeNode node = new TreeNode(Integer.valueOf(str));
node.left = dfs(strs, i);
node.right = dfs(strs, i);
return node;
}
}
49.从根节点到叶节点的路径数字之和
package com.lxh.tree;
/**
* @Author: Tiger
* @Description: 面试题49:从根节点到叶节点的路径数字之和
* @Date: 下午 14:45 2021/11/16 0016
**/
public class SumOfThePathNumbers49 {
public int sumNumbers(TreeNode root) {
return dfs(root, 0);
}
private int dfs(TreeNode root, int path) {
if (root == null) {
return 0;
}
path = path * 10 + root.val;
if (root.left == null && root.right == null) {
return path;
}
return dfs(root.left, path) + dfs(root.right, path);
}
}
50.向下的路径节点值之和
package com.lxh.tree;
import java.util.HashMap;
import java.util.Map;
/**
* @Author: Tiger
* @Description: 面试题50:向下的路径节点值之和
* @Date: 下午 15:03 2021/11/16 0016
**/
public class SumOfTheNodeValues50 {
public int pathSum(TreeNode root, int sum) {
Map<Integer, Integer> map = new HashMap<>();
map.put(0, 1);
return dfs(root, sum, map, 0);
}
private int dfs(TreeNode root, int sum, Map<Integer, Integer> map, int path) {
if (root == null) {
return 0;
}
path += root.val;
int count = map.getOrDefault(path - sum, 0);
map.put(path, map.getOrDefault(path, 0) + 1);
count += dfs(root.left, sum, map, path);
count += dfs(root.right, sum, map, path);
map.put(path, map.get(path) - 1);
return count;
}
public static void main(String[] args) {
SumOfTheNodeValues50 sotnv50 = new SumOfTheNodeValues50();
TreeNode node1 = new TreeNode(5);
TreeNode node2 = new TreeNode(2);
TreeNode node3 = new TreeNode(4);
TreeNode node4 = new TreeNode(1);
TreeNode node5 = new TreeNode(6);
TreeNode node6 = new TreeNode(3);
TreeNode node7 = new TreeNode(7);
node1.left = node2;
node1.right = node3;
node2.left = node4;
node2.right = node5;
node3.left = node6;
node3.right = node7;
int i = sotnv50.pathSum(node1, 8);
System.out.println(i);
}
}
50.二叉树的深度优先搜索
package com.lxh.tree;
import java.util.LinkedList;
import java.util.List;
import java.util.Stack;
/**
* @Author: Tiger
* @Description: 深度优先搜索 - 前序遍历
* @Date: 下午 15:15 2021/11/15 0015
**/
public class PreorderTraversal {
/* 递归形式
public List<Integer> preorderTraversal(TreeNode root) {
List<Integer> nodes = new LinkedList<>();
dfs(root, nodes);
return nodes;
}
private void dfs(TreeNode root, List<Integer> nodes) {
if (root != null) {
nodes.add(root.val);
dfs(root.left, nodes);
dfs(root.right, nodes);
}
}*/
public List<Integer> preorderTraversal(TreeNode root) {
List<Integer> nodes = new LinkedList<>();
Stack<TreeNode> stack = new Stack<>();
TreeNode cur = root;
while (cur != null || !stack.isEmpty()) {
while (cur != null) {
nodes.add(cur.val);
stack.push(cur);
cur = cur.left;
}
cur = stack.pop();
cur = cur.right;
}
return nodes;
}
}
package com.lxh.tree;
import java.util.LinkedList;
import java.util.List;
import java.util.Stack;
/**
* @Author: Tiger
* @Description: 深度优先搜索 - 中序遍历
* @Date: 下午 14:51 2021/11/15 0015
**/
public class InorderTraversal {
/* 递归的形式
public List<Integer> inorderTraversal(TreeNode root) {
List<Integer> nodes = new LinkedList<>();
dfs(root, nodes);
return nodes;
}
private void dfs(TreeNode root, List<Integer> nodes) {
if (root != null) {
dfs(root.left, nodes);
nodes.add(root.val);
dfs(root.right, nodes);
}
}*/
//非递归的形式 即用到了栈
public List<Integer> inorderTraversal(TreeNode root) {
List<Integer> nodes = new LinkedList<>();
Stack<TreeNode> stack = new Stack<>();
TreeNode cur = root;
while (cur != null || !stack.isEmpty()) {
while (cur != null) {
stack.push(cur);
cur = cur.left;
}
cur = stack.pop();
nodes.add(cur.val);
cur = cur.right;
}
return nodes;
}
}
package com.lxh.tree;
import java.util.LinkedList;
import java.util.List;
import java.util.Stack;
/**
* @Author: Tiger
* @Description: 深度优先搜索 - 后续遍历
* @Date: 下午 15:26 2021/11/15 0015
**/
public class PostorderTraversal {
/* 递归的形式
public List<Integer> postorderTraversal(TreeNode root) {
List<Integer> nodes = new LinkedList<>();
dfs(root, nodes);
return nodes;
}
private void dfs(TreeNode root, List<Integer> nodes) {
if (root != null) {
dfs(root.left, nodes);
dfs(root.right, nodes);
nodes.add(root.val);
}
}*/
public List<Integer> postorderTraversal(TreeNode root) {
List<Integer> nodes = new LinkedList<>();
Stack<TreeNode> stack = new Stack<>();
TreeNode cur = root;
TreeNode prev = null;
while (cur != null || !stack.isEmpty()) {
while (cur != null) {
stack.push(cur);
cur = cur.left;
}
cur = stack.peek();
if (cur.right != null && cur.right != prev) {
cur = cur.right;
}else {
stack.pop();
nodes.add(cur.val);
prev = cur;
cur = null;
}
}
return nodes;
}
}