目录
最近的几场笔试以及面试充分暴露了我算法实在是太差了事实。
经过反思,我决定在这一周刷下几种我比较薄弱的题目。
1、栈:leetcode中简单的栈相关的题一共有7道,我再选择三个中等难度的题目,一共10道
2、堆:leetcode中只有一道简单的题目,再选2道题目中等题目,一共3道
3、队列:2道简单题目,在选2道中等题目,一共4道
4、树:35道简单题目,目测其中有价值的为10道左右,再选5道左右,共计15道
5、哈希表:41道简单题目,再选3道中等题目
6、 链表:10道简单题目
7、贪心算法:7道简单题目,再选3道中等题目
8、 动态规划:8道简单题目,再选2道中等题目
本周任务暂时这么多啦,开始刷题。
栈
(20)有效的括号
题目
给定一个只包括 '('
,')'
,'{'
,'}'
,'['
,']'
的字符串,判断字符串是否有效。
有效字符串需满足:
- 左括号必须用相同类型的右括号闭合。
- 左括号必须以正确的顺序闭合。
注意空字符串可被认为是有效字符串。
解析
这一题的思路有点像是消消乐,如果有相互对应的则消掉。因此,我使用了栈这个数据结构来进行操作。
1、首先将‘1’压入栈中;
2、将字符串转数组进行遍历;
3、如果栈顶中的是‘[’或者‘[’或者'{',而字符串中当前遍历到的是对应的右半部分,则将栈顶中的pop出去。
4、否则则将当前遍历到的给压入栈。
5、当全部都遍历完之后,如果栈顶为‘1’,则返回true,否则返回false;
代码如下:
class Solution {
public boolean isValid(String s) {
Stack<Character> stack = new Stack<>();
if(s.isEmpty()){
return true;
}
char[] ch = s.toCharArray();
stack.push('1');
stack.push(ch[0]);
for(int i=1;i<s.length();i++){
if(stack.peek()=='('&&ch[i]==')'){
stack.pop();
continue;
}else if(stack.peek()=='['&&ch[i]==']'){
stack.pop();
continue;
}else if(stack.peek()=='{'&&ch[i]=='}'){
stack.pop();
continue;
}
else {
stack.push(ch[i]);
}
}
if(stack.peek()=='1'){
return true;
}
return false;
}
}
(496)下一个更大元素I
题目
给定两个没有重复元素的数组 nums1
和 nums2
,其中nums1
是 nums2
的子集。找到 nums1
中每个元素在 nums2
中的下一个比其大的值。
nums1
中数字 x 的下一个更大元素是指 x 在 nums2
中对应位置的右边的第一个比 x 大的元素。如果不存在,对应位置输出-1。
分析
我在写这道题的之后的第一反应是通过遍历来进行寻找。现在nums2中寻找和nums1[i]相同的数字,然后继续向后寻找比nums1[i]大的数字。于是第一个代码很快就写好啦
class Solution {
public int[] nextGreaterElement(int[] nums1, int[] nums2) {
int count=0;
int[] result = new int[nums1.length];
for(int i=0;i<nums1.length;i++){
for(int j=0;j<nums2.length;j++){
if(nums1[i]==nums2[j]){
int flag=0;
for(int k=j;k<nums2.length;k++){
if(nums2[k]>nums1[i]){
result[i]=nums2[k];
flag=1;
break;
}
}
if(flag==0){
result[i]=-1;
}
break;
}
}
}
return result;
}
}
但是既然是栈的 相关题目,那就需要用到和栈相关的东西。遍历nums2中所有的数值,如果
代码
class Solution {
public int[] nextGreaterElement(int[] nums1, int[] nums2) {
if(nums2==null || nums2.length==0)return new int[]{};//如果数组2为空,则返回一个空数组
Stack<Integer> stack = new Stack<Integer>();
HashMap<Integer,Integer> hm = new HashMap<Integer,Integer>();
int[] result = new int[nums1.length];
for(int num : nums2){
while(!stack.isEmpty()&&stack.peek()<num){
hm.put(stack.pop(),num);
}
stack.push(num);
}
for(int i=0;i<nums1.length;i++){
result[i] = hm.getOrDefault(nums1[i],-1);
}
return result;
}}
(844) 比较含空格的字符串
题目
给定 S
和 T
两个字符串,当它们分别被输入到空白的文本编辑器后,判断二者是否相等,并返回结果。 #
代表退格字符。
分析
这道题目是很典型的栈的问题。如果遇到#就出栈,遇到其他元素就进栈。但是需要注意的是,在每一次进行pop操作的时候需要判断一下这个栈是否为空。如果为空,则不能进行操作。这点我也踩了坑,还有if条件,小bug改了好久,十分难受。
代码
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
//递归
/* public boolean isDuichen(TreeNode r1,TreeNode r2){
if(r1==null&&r2==null){
return true;
}
else if(r1!=null&&r2!=null&&r1.val==r2.val){
return isDuichen(r1.left,r2.right)&&isDuichen(r1.right,r2.left);
}
return false;
}
public boolean isSymmetric(TreeNode root) {
if (isDuichen(root,root)) return true;
else return false;
}*/
//递推
public boolean isSymmetric(TreeNode root) {
Stack<TreeNode> stack = new Stack<TreeNode>();
stack.add(root);
while(!stack.isEmpty()){
Stack<TreeNode> tmpStack = new Stack<TreeNode>();
while(!stack.isEmpty()){
TreeNode node = stack.pop();
if(node != null){
tmpStack.push(node.left);
tmpStack.push(node.right);
}
}
for(int i = 0, size = tmpStack.size(); i < size/2; i++){
TreeNode left = tmpStack.get(i);
TreeNode right = tmpStack.get(size-1-i);
if(!(left == right || (left != null && right != null && left.val == right.val))){
return false;
}
}
stack = tmpStack;
}
return true;
}
}
堆
(703)数据流中第K大的元素
题目
设计一个找到数据流中第K大元素的类(class)。注意是排序后的第K大元素,不是第K个不同的元素。
你的 KthLargest
类需要一个同时接收整数 k
和整数数组nums
的构造器,它包含数据流中的初始元素。每次调用 KthLargest.add
,返回当前数据流中第K大的元素。
分析
这道题目很明显可以用最大堆来实现。首先在JAVA中使用优先队列构建一个长度为k的最大堆,每次加入数据的时候,如果堆此时的长度不足k则直接offer进去,如果大于k,则和队首比较,如果小于队首,就不管,大于队首就弹出队首。
//我特么写的没保存???????校园网垃圾
代码
class KthLargest {
public int k;
public PriorityQueue<Integer> q;
public KthLargest(int k, int[] nums) {
this.k = k;
q=new PriorityQueue<Integer>(k);
for(int i:nums) add(i);
}
public int add(int val) {
if(q.size()<k){
q.offer(val);
}
else if(q.peek()<val){
q.poll();
q.offer(val);
}
return q.peek();
}
}
/**
* Your KthLargest object will be instantiated and called as such:
* KthLargest obj = new KthLargest(k, nums);
* int param_1 = obj.add(val);
*/
树
(100)相同的树
题目
给定两个二叉树,编写一个函数来检验它们是否相同。
如果两个树在结构上相同,并且节点具有相同的值,则认为它们是相同的。
示例 1:
输入: 1 1 / \ / \ 2 3 2 3 [1,2,3], [1,2,3] 输出: true
示例 2:
输入: 1 1 / \ 2 2 [1,2], [1,null,2] 输出: false
示例 3:
输入: 1 1 / \ / \ 2 1 1 2 [1,2,1], [1,1,2] 输出: false
分析
通过递归。众所周知,一种遍历没法决定一个二叉树的结构。因此需要用不同的遍历方法进行遍历才能对两个二叉树是否相同进行评判。
代码
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public boolean isSameTree(TreeNode p, TreeNode q) {
if(p==null&&q==null){
return true;
}
if(p!=null && q!=null && p.val == q.val){
return isSameTree(p.left,q.left)&&isSameTree(p.right,q.right);
}
else return false;
}
}
(101) 对称二叉树
题目
给定一个二叉树,检查它是否是镜像对称的。
例如,二叉树 [1,2,2,3,4,4,3]
是对称的。
1 / \ 2 2 / \ / \ 3 4 4 3
但是下面这个 [1,2,2,null,3,null,3]
则不是镜像对称的:
1 / \ 2 2 \ \ 3 3
分析
这个有两种思路,一是递归,二是递推。
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
//递归
/* public boolean isDuichen(TreeNode r1,TreeNode r2){
if(r1==null&&r2==null){
return true;
}
else if(r1!=null&&r2!=null&&r1.val==r2.val){
return isDuichen(r1.left,r2.right)&&isDuichen(r1.right,r2.left);
}
return false;
}
public boolean isSymmetric(TreeNode root) {
if (isDuichen(root,root)) return true;
else return false;
}*/
//递推
public boolean isSymmetric(TreeNode root) {
Stack<TreeNode> stack = new Stack<TreeNode>();
stack.add(root);
while(!stack.isEmpty()){
Stack<TreeNode> tmpStack = new Stack<TreeNode>();
while(!stack.isEmpty()){
TreeNode node = stack.pop();
if(node != null){
tmpStack.push(node.left);
tmpStack.push(node.right);
}
}
for(int i = 0, size = tmpStack.size(); i < size/2; i++){
TreeNode left = tmpStack.get(i);
TreeNode right = tmpStack.get(size-1-i);
if(!(left == right || (left != null && right != null && left.val == right.val))){
return false;
}
}
stack = tmpStack;
}
return true;
}
}
(104) 二叉树的最大深度
题目
给定一个二叉树,找出其最大深度。
二叉树的深度为根节点到最远叶子节点的最长路径上的节点数。
说明: 叶子节点是指没有子节点的节点。
示例:
给定二叉树 [3,9,20,null,null,15,7]
,
3 / \ 9 20 / \ 15 7
返回它的最大深度 3 。
分析
也是有两种,分别是递归和递推
代码
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
//递归
/*public int maxDepth(TreeNode root) {
return root == null?0:Math.max(maxDepth(root.left),maxDepth(root.right))+1;
}*/
//递推
public int maxDepth(TreeNode root) {
int depth = 0;
if(root == null)
return depth;
Queue<List<TreeNode>> queue = new LinkedList<>();
//每层用单独链表存储
List<TreeNode> level = new ArrayList<>();
level.add(root);
//初始化队列
queue.offer(level);
//轮询队列
while(!queue.isEmpty()){
depth++;
level = queue.poll();
//存储下一层节点链表
List<TreeNode> levelChildList = new ArrayList<>();
//遍历当前层并放入下一层节点链表
for(TreeNode node:level){
if(node.left != null){
levelChildList.add(node.left);
}
if(node.right!=null){
levelChildList.add(node.right);
}
}
if(levelChildList.size() > 0){
queue.offer(levelChildList);
}
}
return depth;
}
}