剑指Offe(简单)
JZ3 从尾到头打印链表
错误
import java.util.ArrayList;
public class Solution {ArrayList<Integer> arrayList=new ArrayList<Integer>();public ArrayList<Integer> printListFromTailToHead(ListNode listNode) {if (listNode.next!= null) {printListFromTailToHead(listNode.next);}arrayList.add(listNode.val);return arrayList;}}
解答:
ListNode a =null;printListFromTailToHead(a);
调用时候:
由于:listNode.next!= null
得 : null.next!= null
对空操作,空指针异常,报错
所以不能以listNode.next!= null作为判断条件
正确
import java.util.ArrayList;
public class Solution {ArrayList<Integer> arrayList=new ArrayList<Integer>();public ArrayList<Integer> printListFromTailToHead(ListNode listNode) {if (listNode!= null) {printListFromTailToHead(listNode.next);arrayList.add(listNode.val);}return arrayList;}
}
思想
递归的时候 :判断本身是否为null
调用的时候再: 方法(本身.下一个)
JZ5 用两个栈实现队列
import java.util.Stack;public class Solution {Stack<Integer> stack1 = new Stack<Integer>();Stack<Integer> stack2 = new Stack<Integer>();public void push(int node) {stack1.push(node);}public int pop() {if(stack2.isEmpty()){while(stack1.size()!=0){stack2.push(stack1.pop());}return stack2.pop();}else{return stack2.pop();}}
}
注意
pop的时候还要先判断stack2有没有值先
Stack<Integer> stack3 = new Stack<Integer>();
stack3.push(1);
stack3.push(2);for(Integer i:stack3){System.out.println(i);
}
结果
1
2
用foreach不是先进后出了,只有pop才是先进后出
JZ6 旋转数组的最小数字
思路
import java.util.ArrayList;
public class Solution {public int minNumberInRotateArray(int [] array) {int left = 0; //默认最小的int right = array.length - 1;while (left <= right) { // 说明继续查找int mid = (left + right) / 2;if(array[left]<array[right]){// 左边的数小于右边的数 因为从小到大排序的return array[left];}else if(array[mid]<array[right]){// 中间的数小于右边的数 刷新rightright = mid;}else if(array[mid]>array[right]){// 中间的数大于右边的数 刷新leftleft = mid+1;}else{right--;}}return array[left];}
}
[3,4,5,1,2]
三种情况:
左边小于右边:由于是从小到大排序的,说明此时的数组是后面
的1,2了
中间的数小于右边的数:说明最小的在左边和中间,刷新right
例如【5,1,2,3,4】
中间的数大于右边的数:说明最小的在中间和右边,刷新left
例如[3,4,5,1,2] ,
当left=2,right=3时,mid=2
left = mid;时出来死循环所以要+1逼近
JZ8 跳台阶
解法一(递归:从上往下)
public class Solution {public int jumpFloor(int target) {if (target<=1) {return 1;}return jumpFloor(target-1) + jumpFloor(target-2);}
}
解法二(动态规划:从下往上)
public class Solution {public int jumpFloor(int target) {//斐波那契数列//计算f[5]的时候只用到了f[4]和f[3], 没有用到f[2]...f[0],所以保存f[2]..f[0]是浪费了空间。//只需要用3个变量即可。if (target == 0 || target == 1) {return target;}int a=1;int b=1;int c=0;for(int i=2;i<=target;i++){c=a+b;a=b;b=c;}return c;}
}
JZ9 跳台阶扩展问题
求的是种类所以f(n)=f(n-1)+f(n-2)+……f(1)
解答一
public class Solution {public int jumpFloorII(int target) {//易知 f(n)=f(n-1)+f(n-2)+……f(1)//f(n-1)=f(n-2)+……f(1)//两式相减得f(n)=2f(n-1)return (int) Math.pow(2, target-1);}
}
解法二
public class Solution {public int jumpFloorII(int target) {int res = 0;int sum = 0;int i = 1;while(i <= target) {res = sum + 1; sum += res; //f(n-1)之前的所有i++;}return res;}
}
一阶的时候 f(1) = 1 ;有两阶的时候可以
有 f(2) =1+f(1)=2;有三阶的时候可以有 f(3) = 1+f(2)+f(1)=4…依次内推,有n阶时f(n)=2^(n-1)。
JZ16 合并两个排序的链表
解法一(迭代版本)
public class Solution {ListNode head=new ListNode(-1);public ListNode Merge(ListNode list1,ListNode list2) {ListNode temp=head;while(list1!=null && list2!=null){if(list1.val<list2.val){temp.next=list1;list1=list1.next;}else{temp.next=list2;list2=list2.next;}temp=temp.next;}if(list1==null){temp.next=list2;}if(list2==null){temp.next=list1;}return head.next;}
}
创建哑节点
: 弄个虚拟头节点(哨兵节点)
HeroNode temp = head;
:temp是指针,指向的是head的地址
解法二(递归版本)
public ListNode Merge(ListNode list1,ListNode list2) {if(list1 == null){return list2;}if(list2 == null){return list1;}if(list1.val <= list2.val){list1.next = Merge(list1.next, list2);return list1;}else{list2.next = Merge(list1, list2.next);return list2;}
}
解法三
运用栈
JZ20 包含min函数的栈
错误
import java.util.Stack;public class Solution {Stack<Integer> stack = new Stack<>();Integer min=null;public void push(int node) {if(min == null || min>node){//min=node;}stack.push(node);}public void pop() {stack.pop();}public int top() {int a= stack.peek();return a;}public int min() {return min;}}
因为 min是为变的,当pop出min时,min就变了
正确
private Stack<Integer> main = new Stack<>();private Stack<Integer> min = new Stack<>();public void push(int node) {if(min.isEmpty() || min.peek()>=node){min.push(node);}main.push(node);}public void pop() {if(min.peek() == main.peek())min.pop();main.pop();}public int top() {return main.peek();}public int min() {return min.peek();}
当遇到小点的就压进去,一样的 也要压进去。
取的时候和min栈一样,也要弹出来
JZ39 平衡二叉树
解答
public class Solution {public boolean IsBalanced_Solution(TreeNode root) {if(root==null){return true;}else if(Math.abs(height(root.left)-height(root.right))>1 ){return false;}else{return IsBalanced_Solution(root.left) && IsBalanced_Solution(root.right); // return true;//递归每个节点判断}}public int height(TreeNode root){if (root==null){return 0;}return Math.max( root.left==null? 0 :height(root.left) ,root.right==null? 0 :height(root.right) )+1;}}
//要递归每个节点判断
//return true; 是错误的
return IsBalanced_Solution(root.left) && IsBalanced_Solution(root.right);
JZ36 两个链表的第一个公共结点
思路
a+b == b+a
其实该方法主要就是用链表循环的方式替代了长链表指针先走k步这一步骤。
代码
public class Solution {public ListNode FindFirstCommonNode(ListNode pHead1, ListNode pHead2) {ListNode p1 = pHead1;ListNode p2 = pHead2;while(p1 != p2){p1 = p1 == null?pHead2:p1.next;p2 = p2 == null?pHead1:p2.next;}return p1;}
}
JZ30 连续子数组的最大和
方法一:动态规划
状态定义
:dp[i]表示以i结尾的连续子数组的最大和。所以最终要求dp[n-1]
状态转移方程
:dp[i] = max(array[i], dp[i-1]+array[i])
解释
:如果当前元素为整数,并且dp[i-1]为负数,那么当然结果就是只选当前元素
技巧
:这里为了统一代码的书写,定义dp[i]表示前i个元素的连续子数组的最大和,结尾元素为array[i-1]
class Solution {public int maxSubArray(int[] nums) { int n=nums.length;
int max=nums[0];
int[] dp=new int[n];
dp[0]=nums[0]; for(int i=1;i<n;i++){ dp[i]=Math.max(nums[i],dp[i-1]+nums[i]);
max = Math.max(max, dp[i]);
} return max;}
}
方法二:空间复杂度O(1)解法
思想很简单,就是对下标为i的元素array[i],先试探的加上array[i], 如果和为负数,显然,以i结尾的元素对整个结果不作贡献。
public class Solution {public int FindGreatestSumOfSubArray(int[] array) {int MaxSum = array[0]; int ThisSum= 0; for(int i=0;i<array.length;i++) { ThisSum+= array[i]; if(ThisSum > MaxSum) {MaxSum = ThisSum;}/*如果累加和出现小于0的情况, 则和最大的子序列肯定不可能包含前面的元素, 这时将累加和置0,从下个元素重新开始累加 */if(ThisSum< 0) {ThisSum= 0; } }return MaxSum; }
}
注意
max = array[0] 之所以不定义0,是为了避免所有值都小于0的情况,如果定义array[0],一定能得到最大值
JZ45 扑克牌顺子
描述
现在有2副扑克牌,从扑克牌中随机五张扑克牌,我们需要来判断一下是不是顺子。
有如下规则:
- A为1,J为11,Q为12,K为13,A不能视为14
- 大、小王为 0,0可以看作任意牌
- 如果给出的五张牌能组成顺子(即这五张牌是连续的)就输出true,否则就输出false。
例如:给出数据[6,0,2,0,4]
中间的两个0一个看作3,一个看作5 。即:[6,3,2,5,4]
这样这五张牌在[2,6]区间连续,输出true
数据保证每组5个数字,每组最多含有4个零,数组的数取值为 [0, 13]
代码思路
最大和最小差值应该小于5,因为只有五个数字,加了0也不可能变出花来。
还有一点是,
如果数字重复,那么返回错误即可。
最后就需要判断0的个数,去除0以后的数组,进行排序,最大和最小的差值必须小于5即可(因为0可能充当头尾数)。
import java.util.Arrays;
public class Solution {public boolean IsContinuous(int [] numbers) {int numOfZero=0;Arrays.sort(numbers);for(int i=0;i<4;i++){if(numbers[i]==0){numOfZero++;}else if(numbers[i]==numbers[i+1]){//重复值return false;}}return numbers[4]-numbers[numOfZero]<5;//[6,0,2,0,4] 最大的减去不是0的最小数}
}
JZ59 按之字形顺序打印二叉树
描述
给定一个二叉树,返回该二叉树的之字形层序遍历,(第一层从左向右,下一层从右向左,一直这样交替)
例如:
给定的二叉树是{1,2,3,#,#,4,5}
方法(队列)
用BFS,和JZ59把二叉树打印成多行有点像
//解题思路
:其实就是二叉树的层级遍历,不过是在遍历的时候,需要将偶数层的节点逆序。
//关键点
:每次只处理上次在queue中剩余的节点,这是上一层的所有节点。
// 处理完后刚好将下一层的所有节点(包含null)又全部放了进去。
public class Solution {public ArrayList<ArrayList<Integer> > Print(TreeNode pRoot) {ArrayList<ArrayList<Integer>>res=new ArrayList<>();Queue<TreeNode> q=new LinkedList<>();if(pRoot!=null) q.add(pRoot);while(!q.isEmpty()){ArrayList<Integer>temp=new ArrayList<>();int s=q.size();for(int i=0;i<s;i++){TreeNode node=q.poll();if(res.size()%2==0)//res.size是第几层的意思temp.add(node.val);elsetemp.add(0,node.val);if(node.left!=null)q.add(node.left);if(node.right!=null)q.add(node.right);}res.add(temp);}return res;}}
递归
public class Solution {ArrayList<ArrayList<Integer>> Print(TreeNode pRoot) {ArrayList<ArrayList<Integer>> list = new ArrayList<>();depth(pRoot,1,list);for(int i=0;i<list.size();i++){if(i%2!=0){Collections.reverse(list.get(i));}}return list;}private void depth(TreeNode root, int depth, ArrayList<ArrayList<Integer>> list) {if(root==null)return;if(depth>list.size()){list.add(new ArrayList<Integer>());}list.get(depth-1).add(root.val);depth(root.left,depth+1,list);depth(root.right,depth+1,list);}}
BFS
BFS,其英文全称是Breadth First Search。 BFS并不使用经验法则算法。从算法的观点,所有因为展开节点而得到的子节点都会被加进一个先进先出的队列中。一般的实验里,其邻居节点尚未被检验过的节点会被放置在一个被称为 open 的容器中(例如队列或是链表,而被检验过的节点则被放置在被称为 closed 的容器中。(open-closed表)
广度与深度优先搜索的对比
深度优先搜索用栈(stack)来实现,整个过程可以想象成一个倒立的树形:
1、把根节点压入栈中。
2、每次从栈中弹出一个元素,搜索所有在它下一级的元素,把这些元素压入栈中。并把这个元素记为它下一级元素的前驱。
3、找到所要找的元素时结束程序。
4、如果遍历整个树还没有找到,结束程序。
·
广度优先搜索使用队列(queue)来实现,整个过程也可以看做一个倒立的树形:
1、把根节点放到队列的末尾。
2、每次从队列的头部取出一个元素,查看这个元素所有的下一级元素,把它们放到队列的末尾。并把这个元素记为它下一级元素的前驱。
3、找到所要找的元素时结束程序。
4、如果遍历整个树还没有找到,结束程序。
JZ62 二叉搜索树的第k个结点
描述
给定一棵二叉搜索树,请找出其中的第k小的TreeNode结点。
示例1
输入:{5,3,7,2,4,6,8},3
返回值:4
说明:按结点数值大小顺序第三小结点的值为4
解法一(递归)
//思路:二叉搜索树按照中序遍历的顺序打印出来正好就是排序好的顺序。
// 所以,按照中序遍历顺序找到第k个结点就是结果。
遍历到最小保存起来,index++
public class Solution {int index = 0; //计数器TreeNode KthNode(TreeNode root, int k){if(root != null){ //中序遍历寻找第k个TreeNode node = KthNode(root.left,k);if(node != null)return node;index ++;if(index == k)return root;node = KthNode(root.right,k);if(node != null)return node;}return null;}
}
解法二(非递归)
用栈
import java.util.Stack;
public class Solution {TreeNode KthNode(TreeNode pRoot, int k){if(pRoot == null || k <= 0){return null;}Stack<TreeNode> stack = new Stack<>(); //建立栈TreeNode cur = pRoot;//while 部分为中序遍历while(!stack.isEmpty() || cur != null){ if(cur != null){stack.push(cur); //当前节点不为null,应该寻找左儿子cur = cur.left;}else{cur = stack.pop();//当前节点null则弹出栈内元素,相当于按顺序输出最小值。if(--k == 0){ //计数器功能return cur;}cur = cur.right;}}return null;}
}
//非递归版中序遍历,可以利用栈来模拟递归遍历,首先根入栈,然后令根节点的左孩子不断入栈直到为空,弹出栈顶,令其右孩子入栈,重复以上操作,直到遍历结束或者访问第k个节点为止。
剑指Offe(简单)相关推荐
- leetcode剑指offe刷题-第一题-用两个栈实现队列
leetcode剑指offe刷题-第一题 文章目录 leetcode剑指offe刷题-第一题 前言 一.用两个栈实现队列 1.思路 2.代码如下 总结 前言 记录一下自己刷算法的路程. leetcod ...
- 数组中重复的元素(剑指Offe.03)
数组中重复的元素(剑指Offe.03) 题目描述: 在一个长度为 n 的数组 nums 里的所有数字都在 0-n-1 的范围内.数组中某些数字是重复的,但不知道有几个数字重复了,也不知道每个数字重复了 ...
- 一把王者荣耀的时间打卡剑指 Offer简单入门题
第 1 天栈与队列(简单) 剑指 Offer 09. 用两个栈实现队列 难度简单 用两个栈实现一个队列.队列的声明如下,请实现它的两个函数 appendTail 和 deleteHead ,分别完成在 ...
- 【剑指 Offe】11. 旋转数组的最小数字
题目:剑指 Offer 11. 旋转数组的最小数字 把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转. 给你一个可能存在 重复 元素值的数组 numbers ,它原来是一个升序排列的数 ...
- 剑指offe 和为S的连续正数序列
1.题目 小明很喜欢数学,有一天他在做数学作业时,要求计算出9~16的和,他马上就写出了正确答案是100.但是他并不满足于此,他在想究竟有多少种连续的正数序列的和为100(至少包括两个数).没多久,他 ...
- 剑指Offe 50:数组中重复的数字
第一种方法:遍历一遍数组,依次放入hash表.一旦遇到一个元素哈希表中已经有了,就是第一个重复的数字. class Solution { public:bool duplicate(int numbe ...
- 【剑指 Offe】剑指 Offer 18. 删除链表的节点
目录标题 算法汇总 题目 关键点 代码 1.解体方法 思路 代码 时间和空间复杂度 2.解题方法,如暴力法 思路 代码 时间和空间复杂度 算法汇总 以下是所有算法汇总,包括GitHub源码地址链接:力 ...
- 【剑指 Offe】剑指 Offer 11. 旋转数组的最小数字
目录标题 算法汇总 题目 关键点 代码 1.解体方法 - 二分法 思路 代码 时间和空间复杂度 2.解题方法,如暴力法 思路 代码 时间和空间复杂度 算法汇总 以下是所有算法汇总,包括GitHub源码 ...
- 【剑指 Offe】剑指 Offer 17. 打印从1到最大的n位数
目录标题 算法汇总 题目 关键点 代码 1.解体方法 思路 代码 时间和空间复杂度 2.解题方法,如暴力法 思路 代码 时间和空间复杂度 算法汇总 以下是所有算法汇总,包括GitHub源码地址链接:力 ...
最新文章
- Centos5.6入门学习003之Cenots环境初始化
- ABAP业务涉及到的相关数据库表 .
- https连接java_如何从Java应用程序设置Https连接
- JavaScript prototype 属性
- 无向图的深度优先遍历非递归_LeetCode0429: N叉树的层序遍历
- c语言程序设计第二版课后答案 机械工业出版社,C语言程序设计 第2版
- Xamarin只言片语1——Xamarin下的弹框
- Windows 下80端口被进程 System PID=4 占用的解决方法
- matlab simulink 单气室油气弹簧阻尼特性分析
- 身份证号归属地数据库
- 中职计算机组装与维护实训教案,《计算机组装与维护》——计算机组装与维修的基础知识教学教案(中职教育)...
- SEO项目管理,该问自己的几个问题?
- SAP SD跨公司销售案例教程前台操作
- 网易云精选评论,总有一句戳在你心里
- obs听到了自己的回音_直播连麦过程中回声回音解决方式
- electron + fluent-ffmpeg推送桌面、音视频、窗口
- GWAS 总体流程理解版
- android开发面试题!微信小程序趋势及前景,社招面试心得
- uni-app: IPv4地址代替localhost当做项目接口请求地址,不同工作环境需要配置不同请求地址
- ubuntu远程访问win7登录后语言为繁体字的解决办法