今天没有针对什么专门去做,就是自己剑指还没有刷完的,随便点开五道。
剑指Offer 54.二叉搜索树的第k大节点
解析过程:
要解此题就得知道什么是二叉搜索树,其满足左孩子 <= 根 <= 右孩子。所以我们要是对其进行中序遍历的话就会有顺序的进行输出,但是此题要求解的是第k大节点,所以也就是倒数第k个,那么就需要进行二叉树的倒序输出了,[右,根,左]。使用递归去遍历的时候需要注意对其k次进行–操作,对第k个元素信息得保存起来,并返回。
代码实现:
class Solution {
int res,k;
public int kthLargest(TreeNode root, int k) {
this.k = k;
dfs(root);
return res;
}
public void dfs(TreeNode root){
//如果root为null说明已经到了叶子结点了,返回。
if(root == null)return;
//先遍历右子树
dfs(root.right);
//访问根结点,记录访问的次数,对k进行--;
if(--k == 0){
res = root.val;
return;
}
dfs(root.left);
}
}
剑指Offer 39.数组中出现次数超过一半的数字
解析过程:
方式一:HashMap
遍历数组,对所有元素的出现次数进行存储,然后判断次数是否大于数组个数一半,返回。时间复杂度是O(n),空间复杂度也是O(n)。
方式二:排序
题目给定一定存在多数元素,也就是个数大于全部个数一半的数,那么排序之后出现在中间位置上的也就一定是这个数了,懒得写排序过程了,所以就直接Arrays.sort了。
方式三:摩尔投票法
看了大佬的解析,真的很妙!假定众数是x,那么就对其票数加一,如果碰到非众数,就对票数减一,当票数为0时,对将新遍历元素设为众数,再进行判断与计算,那么众数的票数最后一定是>=1的那个。时间复杂度是O(n),空间复杂度是O(1)。
代码实现:
class Solution {
//方式一:HashMap记录
//实现复杂度是O(n),空间复杂度也是O(n)
// Map<Integer,Integer> map;
// public int majorityElement(int[] nums) {
// map = new HashMap<>();
// int res = 0;
// for(int i = 0;i < nums.length;i++){
// map.put(nums[i],map.getOrDefault(nums[i],0)+1);
// if(map.get(nums[i])>nums.length/2){
// res = nums[i];
// break;
// }
// }
// return res;
// }
//方式二:排序
//排序过程懒得写,就Arrays.sort吧,哈哈哈
// public int majorityElement(int[] nums) {
// Arrays.sort(nums);
// return nums[nums.length/2];
// }
//方式三:摩尔投票法
//这个方式是看的大佬解析的,真的厉害,就很妙
public int majorityElement(int[] nums) {
int x = 0, count = 0;
for(int num:nums){
if(count == 0)x = num;
count += x == num ? 1 : -1;
}
return x;
}
}
这个方法果然有点强!
剑指Offer28.对称的二叉树
解析过程:
首先对于根节点来说的话,如果根节点为空,那么这个树我们就可以认为是一个对称的二叉树,如果根节点不为空,那么只需要判断左子树和右子树是否为对称的,然后再去递归判断子树的子树是否为对称的。
当然最后结束条件肯定得到叶子结点了,如果两个都为空,那么说明是对称的,如果只有一个为空或者值不同,说明不对称。
代码实现:
class Solution {
public boolean isSymmetric(TreeNode root) {
if(root == null)return true;
return method(root.left,root.right);
}
public boolean method(TreeNode l,TreeNode r){
if(l == null && r == null)return true;
if(l == null || r == null || l.val != r.val)return false;
return method(l.left,r.right) && method(l.right ,r.left);
}
}
剑指Offer30.包含min函数的栈
解析过程:
这道题真的很简单,我都感觉有点凑数了!
用两个栈来实现对栈中最小值的存放,首先不能单纯的用一个变量来存放最小值,因为栈的特性是先进后出的,如果只是用一个变量来存,那么如果最小值弹出了,此时最小值就需要变化,但是从当下位置往下的所有元素都是随机的,无法找到最小元素(别跟我说遍历)。
所以呢,如果栈为空则最小值栈同样一起压栈,如果不为空,则判断要压栈的元素是不是比当前最小栈中存放的元素还要小,如果是,则压进去。弹栈就是看看当前要栈顶元素是不是最小值栈的栈顶元素即可。
代码实现:
class MinStack {
Deque<Integer> stack1,stack2;
/** initialize your data structure here. */
public MinStack() {
stack1 = new LinkedList<>();
stack2 = new LinkedList<>();
}
public void push(int x) {
stack1.push(x);
if(stack2.isEmpty() || stack2.peek() >= x){
stack2.push(x);
}
}
public void pop() {
if(stack1.pop().equals(stack2.peek())){
stack2.pop();
}
}
public int top() {
return stack1.peek();
}
public int min() {
return stack2.peek();
}
}
剑指Offer62.圆圈中最后剩下的数字
解析过程:
这是一道约瑟夫环问题,这个过程还是比较难想,我觉得它不应该列为简单题。。。
我觉得自己也将的不是很明白,大家可以自己去看看解析。。。
class Solution {
//方式一:递归
// public int lastRemaining(int n, int m) {
// return method(n,m);
// }
// public int method(int n,int m){
// if(n == 1)return 0;
// int x = method(n-1,m);
// return (m+x)%n;
// }
//方式二:迭代
public int lastRemaining(int n, int m) {
int f = 0;
for(int i = 2;i <= n;i++){
f = (f+m)%i;
}
return f;
}
}