37.序列化二叉树
这里要保证输出的格式都一致
public class Codec {
public String serialize(TreeNode root) {
//使用层序遍历
if(root == null) return "[]";
StringBuilder res = new StringBuilder("[");
Queue<TreeNode> queue = new LinkedList<>() {{ add(root); }};
while(!queue.isEmpty()) {
TreeNode node = queue.poll();//先进先出
if(node != null) {
res.append(node.val + ",");
queue.add(node.left);
queue.add(node.right);
}
else res.append("null,");
}
// res.deleteCharAt(res.length() - 1);//删除StringBuilder中还未填值的空间,工程习惯,对算法无影响
res.append("]");
return res.toString();
}
public TreeNode deserialize(String data) {
if(data.equals("[]")) return null;
String[] vals = data.substring(1, data.length() - 1).split(","); //substring(1,n-1)是去掉[],vals 是字符数组
TreeNode root = new TreeNode(Integer.parseInt(vals[0]));
Queue<TreeNode> queue = new LinkedList<>() {{ add(root); }};
int i = 1;
while(!queue.isEmpty()) {
TreeNode node = queue.poll();
//左节点
if(!vals[i].equals("null")) {
node.left = new TreeNode(Integer.parseInt(vals[i]));//
queue.add(node.left);
}
i++;
//右节点
if(!vals[i].equals("null")) {
node.right = new TreeNode(Integer.parseInt(vals[i]));
queue.add(node.right);
}
i++;
}
return root;
}
}
38,字符串的排列(有难度)
class Solution {
List<String> res = new LinkedList<>();
char[] c;
public String[] permutation(String s) {
c = s.toCharArray();
dfs(0);
return res.toArray(new String[res.size()]);
}
void dfs(int x) {
if(x == c.length - 1) {
res.add(String.valueOf(c)); // 添加排列方案
return;
}
HashSet<Character> set = new HashSet<>();//为什么每进入一次dfs都要开辟一个set空间。因为set的存储方式不会将原来位置的值覆盖掉。而如果完全相同则是存储失败。
for(int i = x; i < c.length; i++) {
if(set.contains(c[i])) continue; // 重复,因此剪枝
set.add(c[i]);
swap(i, x); // 交换,将 c[i] 固定在第 x 位
dfs(x + 1); // 开启固定第 x + 1 位字符
swap(i, x); // 恢复交换
}
}
void swap(int a, int b) {
char tmp = c[a];
c[a] = c[b];
c[b] = tmp;
}
}
39 数组中出现次数超过一半的数字
class Solution {
public int majorityElement(int[] nums) {
Map<Integer, Integer> counts = new HashMap<>();
for(int i = 0;i<nums.length;i++){
int count = counts.getOrDefault(nums[i], 0) + 1;//当有nums[i]时,就是用其对应的value值(初始counts是没有赋值的,所以value都为0,key初始也为0 ,因为Integer型),尾部+1记录出现的次数,最小值为1
counts.put(nums[i],count);
if (count > nums.length / 2)
return nums[i];
}
return -1;
}
}
40,最小的k个数
直接调用排序
class Solution {
public int[] getLeastNumbers(int[] arr, int k) {
Arrays.sort(arr);
int[] minarr = new int[k];
for(int i =0;i<k;i++)
minarr[i] = arr[i];
return minarr;
}
}
41.数据流中的中位数(堆)
构建两个优先级队列(堆)A,B;A小顶堆存放较大的一半,B大顶堆存放较小的一半
添加操作:要保证添加数据之后依然保持中位数特点
class MedianFinder {
Queue<Integer> A, B;
public MedianFinder() {
A = new PriorityQueue<>(); // 小顶堆,保存较大的一半
B = new PriorityQueue<>(Comparator.reverseOrder()); // 大顶堆,保存较小的一半
}
//为什么要有A加入再删除或者B加入再删除动作?是为了在堆中进行排序,加入堆中的元素要按顺序排序
public void addNum(int num) {
if(A.size() != B.size()) {
A.add(num);
B.add(A.poll());
} else {
B.add(num);
A.add(B.poll());
}
}
public double findMedian() {
return A.size() != B.size() ? A.peek() : (A.peek() + B.peek()) / 2.0;
}
}
42.连续子数组的最大和
动态规划
当dp[i−1]>0 时:执行 dp[i] = dp[i-1] + nums[i];
当 dp[i−1]≤0 时:执行 dp[i] = nums[i];
class Solution {
public int maxSubArray(int[] nums) {
int res = nums[0];
for(int i=1;i<nums.length;i++){
nums[i] += Math.max(nums[i-1],0);
res = Math.max(res,nums[i]);
}
return res;
}
}
还可以用求解
如果此道题还要求输出最大子数组,可以提升为中等难度。