文章目录
二刷
JZ48最长不含重复字符的子字符串
JZ31 栈的压入弹出序列
JZ36 二叉搜索树与双向链表
(注意dfs的使用)
Math用法
Math.round()//函数是取最接近整数,如果遇到一样近,则取最大值
Math.abs()//取绝对值
Math.max()//取较大值
iterator迭代器遍历
TreeSet<Integer> set=new TreeSet<>();
//正序遍历
Iterator<Integer> it=set.iterator();
//逆序遍历
Iterator<Integer> it1=set.descendingIterator();
Random用法
Random random=new Random();
//生成[0,100)之间的随机数
int i = random.nextInt(100);
1.Scanner用法
//以上是scanner的常用用法
Scanner sc=new Scanner(System.in);
while (sc.hasNextInt()){
int i = sc.nextInt();
System.out.println(i);
}
sc.close();
/***************************/
//判断是否还有输入
sc.hasNext()
//以字符串的方式接收
String str=sc.next();
//判断是否还有下一行输入
sc.hasNextLine();
//以每一行的整体作为一个字符串
String str=sc.nextLine();
2.Integer用法
//此方法可以将一个int类型整数转为二进制数并用String类型输出,其中正数用原码形式,负数用补码
String s = Integer.toBinaryString(i);
//此方法求整数n二进制数中1的个数
int count = Integer.bitCount(n);
//此方法将字符串转为整数i
int i=Integer.parseInt(str)
//该方法可以解析十六进制数的字符串,转换为integer
Integer decode = Integer.decode("0x11");
3.String用法
//String的用法:
//java中String是只读的,没有办法进行变换,因此需要使用StringBuilder。
String.length() //获取字符串的长度
String.charAt(i) //获取第i个字符的内容
String.subString(start) //获取[start,)的字符串
String.subString(start,end) //获取[start,end)中的字符串
String[] str=String.split(" ") //用空格进行分割,返回分割后的String数组
char[] c = iniString.toCharArray() //将字符串转为char数组来进行改变字符内容
String.equal() //判断两个字符串是否相等
String.trim()//可以去掉字符串前面和后面的空格
String.startsWith("abc")//判断字符串String是否为"abc"开头
//StringBuilder的用法:
除了String中支持的方法外,StringBuilder支持字符的增、删、改。
stringBuilder.append("we"); //添加we在词尾
stringBuilder.insert(0,"we");//在0的位置加入后面的内容
stringBuilder.delete(0,1); //删除[0,1)的数据
stringBuilder.deleteCharAt(0);
stringBuilder.setCharAt(0,'p'); //在某一个独特位置设置字符
char c = stringBuilder.charAt(i);//查询某个位置上的字符
System.out.println(stringBuilder);
new String(stringBuilder);//用stringBuilder来初始化String
stringBuilder.reverse();//将sb中的字符串反转,可以用来判断回文字符串
3.类型转换的方法
//int转string
String str=123+"";
//char转int
char c='2';
int i=c-'0';
4.Collections&Arrays
//直接整数转化为数组
List<Integer> list = Arrays.asList(1, 2, 3);
//对数组a进行升序排序
Arrays.sort(int[]a)
//复制int[]arr中的元素,包括from处元素,不包括to
Arrays.copyOfRange(arr,from,to)
//默认自然升序排序
Collections.sort(list)
//通过匿名内部类实现降序排序
Collections.sort(list, new Comparator<>() {
@Override
public int compare(Integer o1, Integer o2) {
return o1-o2;//升序
return o2-o1;//降序
}
});
5.queue相关
//queue的实现方式
//LinkedList为正常的先进先出,线程不安全
Queue<TreeNode> queue=new LinkedList<>();
//优先队列,会将里面元素按照升序排列
Queue<Integer> queue=new PriorityQueue<>();
//按照降序排列
Queue<Integer> queue=new PriorityQueue<>((o1, o2) -> o2-o1);
JZ4
题目:
输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建二叉树并返回。
思路:
根据中序遍历和先序遍历可以确定二叉树,具体过程为:
1.根据先序序列第一个结点确定根结点
2.根据根结点在中序序列中的位置分割出左右两个子序列
3.对左子树和右子树分别递归使用同样的方法继续分解
/**
* Definition for binary tree
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
import java.util.Arrays;
public class Solution {
public TreeNode reConstructBinaryTree(int [] pre,int [] in) {
if(pre.length==0||in.length==0){
return null;
}
TreeNode root=new TreeNode(pre[0]);
for(int i=0;i<in.length;i++){
if(pre[0]==in[i]){
root.left=reConstructBinaryTree(Arrays.copyOfRange(pre,1,i+1),Arrays.copyOfRange(in,0,i));
root.right=reConstructBinaryTree(Arrays.copyOfRange(pre,i+1,pre.length),Arrays.copyOfRange(in,i+1,in.length));
}
}
return root;
}
}
JZ23
题目:
输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果。如果是则返回true,否则返回false。假设输入的数组的任意两个数字都互不相同。
思路:
首先对二叉搜索树后序遍历要了解清楚,根节点在最后一位,通过判断节点的大小可以划分出左右子树,然后递归判断即可
public class Solution {
public boolean VerifySquenceOfBST(int [] sequence) {
if(sequence==null||sequence.length==0)
return false;
return HelpVerify(sequence,0,sequence.length-1);
}
public boolean HelpVerify(int[] sequence,int start,int root){
if(start>=root)return true;
//找到左右子树的分界点i
int i;
for(i=start;i<root;i++){
if(sequence[i]>sequence[root])
break;
}
//判断右子树的所有节点是否小于根节点,r如果有则返回false
for(int j=i;j<root;j++){
if(sequence[j]<sequence[root])
return false;
}
return HelpVerify(sequence,start,i-1)&&HelpVerify(sequence,i,root-1);
}
}
JZ26
题目:
输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的双向链表。要求不能创建任何新的结点,只能调整树中结点指针的指向。
思路:
根据二叉搜索树的特性,用中序遍历可得出排序的节点,将这些排好序的节点存储起来,再构建双向链表即可
import java.util.*;
/**
public class TreeNode {
int val = 0;
TreeNode left = null;
TreeNode right = null;
public TreeNode(int val) {
this.val = val;
}
}
*/
public class Solution {
public TreeNode Convert(TreeNode pRootOfTree) {
if(pRootOfTree==null)
return null;
ArrayList<TreeNode> list=new ArrayList<>();
inOrder(pRootOfTree,list);
//构建双向链表
for(int i=0;i<list.size()-1;i++){
list.get(i).right=list.get(i+1);
list.get(i+1).left=list.get(i);
}
return list.get(0);
}
public void inOrder(TreeNode node,ArrayList<TreeNode> list){
if(node!=null){
inOrder(node.left,list);
list.add(node);
inOrder(node.right,list);
}
}
}
总结:
掌握二叉树的先中后序遍历代码
JZ27
题目:
输入一个字符串,按字典序打印出该字符串中字符的所有排列。例如输入字符串abc,则按字典序打印出由字符a,b,c所能排列出来的所有字符串abc,acb,bac,bca,cab和cba。
思路:
import java.util.*;
public class Solution {
public ArrayList<String> Permutation(String str) {
ArrayList<String> result=new ArrayList<>();
if(str==null||str.length()==0)
return result;
else{
Help(0,str.toCharArray(),result);
/*按照字典序排序
*此处也可以利用TreeSet来排序
*TreeSet可以自动降重和字典序排序
*/
Collections.sort(result);
}
return result;
}
public void Help(int i,char[] chr,ArrayList<String> result){
if(i==chr.length-1){
String value=String.valueOf(chr);
if(!result.contains(value)){
result.add(value);
}
}else{
for(int j=i;j<chr.length;j++){
Swap(i,j,chr);//依次选一个数固定住
Help(i+1,chr,result);//让后面的数进行全排列
Swap(j,i,chr);//恢复原来的模样
}
}
}
public void Swap(int i,int j,char[] chr){
char temp=chr[i];
chr[i]=chr[j];
chr[j]=temp;
}
}
JZ30
题目:
输入一个整型数组,数组里有正数也有负数。数组中的一个或连续多个整数组成一个子数组。求所有子数组的和的最大值。要求时间复杂度为 O(n).
思路:
动态规划。dp[n]代表以当前元素为截止点的连续子序列的最大和,如果dp[n-1]>0,dp[n]=array[n]+dp[n-1],因为当前数字加上一个正数一定会变大;如果dp[n-1]<0,dp[n]=array[n],因为当前数字加上一个负数一定会变小。使用一个变量max记录最大的dp值返回即可
public class Solution {
public int FindGreatestSumOfSubArray(int[] array) {
if(array==null|array.length==0)
return 0;
int[] dp=new int[array.length];
dp[0]=array[0];
int max=dp[0];
for(int i=1;i<array.length;i++){
dp[i]=array[i]+(dp[i-1]>0?dp[i-1]:0);
max=max>dp[i]?max:dp[i];
}
return max;
}
}
总结:
这道题用到了动态规划,第一次接触动态规划不是很理解,后面要多练习
JZ32
题目:
输入一个正整数数组,把数组里所有数字拼接起来排成一个数,打印能拼接出的所有数字中最小的一个。例如输入数组{3,32,321},则打印出这三个数字能排成的最小数字为321323。
思路:
比较两个字符串s1,
s2大小的时候,先将它们拼接起来,比较s1+s2,和s2+s1那个大,如果s1+s2大,那说明s2应该放前面,所以按这个规则,s2就应该排在s1前面
import java.util.ArrayList;
public class Solution {
public String PrintMinNumber(int [] numbers) {
if(numbers==null||numbers.length==0)
return "";
int temp;
int i,j;
for(i=0;i<numbers.length;i++){
for(j=0;j<numbers.length-1-i;j++){
if(judge(numbers[j],numbers[j+1])){
temp=numbers[j];
numbers[j]=numbers[j+1];
numbers[j+1]=temp;
}
}
}
String str=new String("");
for(i=0;i<numbers.length;i++){
str+=numbers[i];
}
return str;
}
public boolean judge(int a,int b){
String sum1=a+""+b;
String sum2=b+""+a;
if(sum1.compareTo(sum2)>0)
return true;
else
return false;
}
}
总结:
1.可以用int+""+int 的方式将int拼接为string
2.str1.compareTo(str2)方法可以比较字符串的大小。相等返回0,str1>str2返回大于0,str1<str2返回小于0。
JZ33
题目:
把只包含质因子2、3和5的数称作丑数(Ugly Number)。例如6、8都是丑数,但14不是,因为它包含质因子7。 习惯上我们把1当做是第一个丑数。求按从小到大的顺序的第N个丑数。
思路:
一个丑数成以2/3/5,得到的还是一个丑数;有3个对列p2/p3/p5,每次都取最小的数,放到数组中。
public class Solution {
public int GetUglyNumber_Solution(int index) {
if(index<=0)return 0;
int p2=0,p3=0,p5=0;
int[]result=new int[index];
result[0]=1;
for(int i=1;i<index;i++){
result[i]=Math.min(result[p2]*2,Math.min(result[p3]*3,result[p5]*5));
if(result[i] == result[p2]*2)p2++;//为了防止跳过丑数需要三个if都能够走到
if(result[i] == result[p3]*3)p3++;
if(result[i] == result[p5]*5)p5++;
}
return result[index-1];
}
}
JZ34
题目:
在一个字符串(0<=字符串长度<=10000,全部由字母组成)中找到第一个只出现一次的字符,并返回它的位置, 如果没有则返回 -1(需要区分大小写).(从0开始计数)
思路:
用一个数组按照字符出现的顺序存储每一个字符出现的次数,然后再遍历这个数组,输出一个出现次数为1字符的索引
public class Solution {
public int FirstNotRepeatingChar(String str) {
if(str==null || str.length() == 0)return -1;
int[] count = new int['z'+1];
//用一个类似hash的东西来存储字符出现的次数,很方便
for(int i=0; i < str.length();i++)
count[str.charAt(i)]++;
//其实这个第二步应该也是ka我的地方,没有在第一时间想到只要在遍历一遍数组并访问hash记录就可以了
for(int i=0; i < str.length();i++)
if(count[str.charAt(i)]==1)
return i;
return -1;
}
}
总结:
count[‘a’]等价于count[97]。count[str.charAt(i)]++;可以非常巧妙的按照顺序统计每个字符出现的次数。
JZ38
题目:
输入一棵二叉树,求该树的深度。从根结点到叶结点依次经过的结点(含根、叶结点)形成树的一条路径,最长路径的长度为树的深度。
思路1:
这里用层序遍历的思想,遍历了一层让high++;
import java.util.*;
/**
public class TreeNode {
int val = 0;
TreeNode left = null;
TreeNode right = null;
public TreeNode(int val) {
this.val = val;
}
}
*/
public class Solution {
public int TreeDepth(TreeNode root) {
if(root==null)
return 0;
Queue<TreeNode> queue=new LinkedList<>();
queue.add(root);
int high=0;
int size;
while(!queue.isEmpty()){
size=queue.size();
while(size!=0){
TreeNode node=queue.poll();
if(node.left!=null)
queue.add(node.left);
if(node.right!=null)
queue.add(node.right);
size--;
}
high++;
}
return high;
}
}
思路2:
还可以采用递归的思想
public int TreeDepth(TreeNode node) {
if (node == null)
return 0;
if (node.left == null && node.right == null)
return 1;
return 1 + Math.max(TreeDepth(node.left), TreeDepth(node.right));
}
JZ39
题目:
输入一棵二叉树,判断该二叉树是否是平衡二叉树。在这里,我们只需要考虑其平衡性,不需要考虑其是不是排序二叉树平衡二叉树(Balanced Binary Tree),具有以下性质:它是一棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树。
思路:
上题求出二叉树的深度,此题目只需判断左右子树的高度差
public class Solution {
public boolean IsBalanced_Solution(TreeNode root) {
if(root==null)
return true;
int left=depth(root.left);
int right=depth(root.right);
if(left-right>1||right-left>1)
return false;
return IsBalanced_Solution(root.left)&&IsBalanced_Solution(root.right);
}
public int depth(TreeNode node){
if(node==null)
return 0;
int left=depth(node.left);
int right=depth(node.right);
return 1+(left>right?left:right);
}
}
JZ46
题目:
首先,让小朋友们围成一个大圈。然后,他随机指定一个数m,让编号为0的小朋友开始报数。每次喊到m-1的那个小朋友要出列唱首歌,然后可以在礼品箱中任意的挑选礼物,并且不再回到圈中,从他的下一个小朋友开始,继续0…m-1报数…这样下去…直到剩下最后一个小朋友,可以不用表演,并且拿到礼物。请你试着想下,哪个小朋友会得到这份礼品呢?(注:小朋友的编号是从0到n-1)
思路:
使用ArrayList存储编号,ArrayList的增删元素的方法较为方便,定义一个指针,每当循环够m次后清零从头开始
import java.util.*;
public class Solution {
public int LastRemaining_Solution(int n, int m) {
if(n<=0||m<=0)
return -1;
ArrayList<Integer> result=new ArrayList<>();
for(int i=0;i<n;i++){
result.add(i);
}
int cur=-1;
while(result.size()>1){
for(int j=0;j<m;j++){
cur++;
if(cur==result.size())
cur=0;
}
result.remove(cur);
cur--;
}
return result.get(0);
}
}
总结:
理解cur- -的用意
JZ47
题目:
求1+2+3+…+n,要求不能使用乘除法、for、while、if、else、switch、case等关键字及条件判断语句(A?B:C)。
思路:
题目要求不能使用关键字判断语句,原本想使用递归,但递归需要if判断递归边界,故使用&&短路与达到判断递归边界的作用
public class Solution {
public int Sum_Solution(int n) {
boolean x=(n>1)&&((n+=Sum_Solution(n-1))>0);
return n;
}
}
JZ48
题目:
写一个函数,求两个整数之和,要求在函数体内不得使用+、-、*、/四则运算符号。
思路:
通过位运算实现。通过简单的验证,可以得到以下规律:执行加法 x ^ y,进位操作 ( x & y ) << 1。概括为:两个二进制的相加结果是用一个异或门实现的;两个二进制的进位结果是用一个与门和向左进位来实现的。
public class Solution {
public int Add(int num1, int num2) {
int result, ans;
do {
result = num1 ^ num2; // 每一位相加
ans = (num1 & num2) << 1; // 进位
num1 = result;
num2 = ans;
} while (ans != 0);
return result;
}
}
JZ49
题目:
将一个字符串转换成一个整数,要求不能使用字符串转换整数的库函数。 数值为0或者字符串不是一个合法的数值则返回0
思路:
使用ASCII码值来进行字符串到整数的转换
public class Solution {
public int StrToInt(String str) {
if(str.length()==0||str==null)
return 0;
int flag=1;
int sum=0;
for(int i=0;i<str.length();i++){
if(i==0&&str.charAt(i)=='+')flag=1;
else if(i==0&&str.charAt(i)=='-')flag=-1;
else{
//字符不是0-9的数字
if(str.charAt(i)-'9'>0||str.charAt(i)-'0'<0)
return 0;
//超出int范围
if(sum>Integer.MAX_VALUE||sum<Integer.MIN_VALUE)
return 0;
sum=sum*10+(str.charAt(i)-'0');
}
}
return sum*flag;
}
}
JZ54
题目:
请实现一个函数用来找出字符流中第一个只出现一次的字符。例如,当从字符流中只读出前两个字符"go"时,第一个只出现一次的字符是"g"。当从该字符流中读出前六个字符“google"时,第一个只出现一次的字符是"l"。
思路:
使用linkedhashmap,linkedhashmap相比于hashmap可以保存数据的插入顺序,在用Iterator遍历LinkedHashMap时,先得到的数据就是先插入的数据,这样解题就比较容易
import java.util.*;
public class Solution {
LinkedHashMap<Character,Integer> map=new LinkedHashMap<>();
//Insert one char from stringstream
public void Insert(char ch)
{
if(map.containsKey(ch))
map.put(ch,-1);
else
map.put(ch,1);
}
//return the first appearence once char in current stringstream
public char FirstAppearingOnce()
{
Iterator<Character> iterator=map.keySet().iterator();
while(iterator.hasNext()){
char cur=iterator.next();
if(map.get(cur)==1)
return cur;
}
return '#';
}
}
JZ56
题目:
在一个排序的链表中,存在重复的结点,请删除该链表中重复的结点,重复的结点不保留,返回链表头指针。 例如,链表1->2->3->3->4->4->5 处理后为 1->2->5
思路:
用LinkedHashMap存储节点并删除重复节点,然后通过遍历map将节点取出,并连接起来
import java.util.*;
/*
public class ListNode {
int val;
ListNode next = null;
ListNode(int val) {
this.val = val;
}
}
*/
public class Solution {
public ListNode deleteDuplication(ListNode pHead)
{
if(pHead==null)
return null;
LinkedHashMap<Integer,ListNode> map=new LinkedHashMap<>();
ListNode p=pHead;
ArrayList<Integer> arr1=new ArrayList<>();
while(p!=null){
//记录重复的节点
if(map.containsKey(p.val))
arr1.add(p.val);
map.put(p.val,p);
p=p.next;
}
//删除重复的节点
for(int i=0;i<arr1.size();i++){
map.remove(arr1.get(i));
}
Iterator<Integer> it=map.keySet().iterator();
ArrayList<ListNode> arr=new ArrayList<>();
//将map中的value按顺序存储在list中
while(it.hasNext()){
arr.add(map.get(it.next()));
}
if(arr.size()==0)
return null;
//将节点建立连接
for(int i=0;i<arr.size()-1;i++){
arr.get(i).next=arr.get(i+1);
}
//最后一个节点指向null
arr.get(arr.size()-1).next=null;
return arr.get(0);
}
}
JZ58
题目:
请实现一个函数,用来判断一棵二叉树是不是对称的。注意,如果一个二叉树同此二叉树的镜像是同样的,定义其为对称的。
思路:
首先要理解对称二叉树的含义,其次用递归就可以算出来
public class Solution {
boolean isSymmetrical(TreeNode pRoot)
{
if(pRoot==null)
return true;
else
return Judge(pRoot.left,pRoot.right);
}
//利用镜像二叉树的性质来判断是否为二叉树
public boolean Judge(TreeNode left,TreeNode right){
if(left==null&&right==null)
return true;
if(left==null||right==null)
return false;
if(left.val==right.val)
return Judge(left.left,right.right)&&Judge(left.right,right.left);
else
return false;
}
}
JZ60
题目:
从上到下按层打印二叉树,同一层结点从左至右输出。每一层输出一行。
思路:
首先想到用BFS,在后序分层时,思路跑偏了,用了比较复杂的方法。比较高效的方法是用queue.size(),可以得到一层的元素的数量,然后通过while循环进行操作。对于有关二叉树的层序遍历的问题,可优先考虑
import java.util.ArrayList;
import java.util.Queue;
import java.util.LinkedList;
/*
public class TreeNode {
int val = 0;
TreeNode left = null;
TreeNode right = null;
public TreeNode(int val) {
this.val = val;
}
}
*/
public class Solution {
ArrayList<ArrayList<Integer> > Print(TreeNode pRoot) {
ArrayList<ArrayList<Integer>> result=new ArrayList<>();
if(pRoot==null)
return result;
Queue<TreeNode> queue=new LinkedList<>();
queue.offer(pRoot);
ArrayList<Integer> newLine;
int size;
while(!queue.isEmpty()){
size=queue.size();
newLine=new ArrayList<>();
while(size>0){
TreeNode node=queue.poll();
newLine.add(node.val);
if(node.left!=null)
queue.offer(node.left);
if(node.right!=null)
queue.offer(node.right);
size--;
}
result.add(newLine);
}
return result;
}
}
JZ61
题目:
二叉树的序列化是指:把一棵二叉树按照某种遍历方式的结果以某种格式保存为字符串,从而使得内存中建立起来的二叉树可以持久保存。序列化可以基于先序、中序、后序、层序的二叉树遍历方式来进行修改,序列化的结果是一个字符串,序列化时通过 某种符号表示空节点(#),以 ! 表示一个结点值的结束(value!)。
二叉树的反序列化是指:根据某种遍历顺序得到的序列化字符串结果str,重构二叉树。
思路:
这里采用BFS的思路,用BFS遍历二叉树,也用BFS建立二叉树
import java.util.*;
/*
public class TreeNode {
int val = 0;
TreeNode left = null;
TreeNode right = null;
public TreeNode(int val) {
this.val = val;
}
}
*/
public class Solution {
private String str;
String Serialize(TreeNode root) {
StringBuilder sb=new StringBuilder();
if(root==null)
return "";
Queue<TreeNode> queue=new LinkedList<>();
queue.offer(root);
sb.append(root.val+",");
while(!queue.isEmpty()){
TreeNode node=queue.poll();
if(node.left!=null||node.right!=null){
if(node.left!=null){
queue.offer(node.left);
sb.append(node.left.val+",");
}
else
sb.append("#,");
if(node.right!=null){
queue.offer(node.right);
sb.append(node.right.val+",");
}
else
sb.append("#,");
}
}
return sb.toString();
}
TreeNode Deserialize(String str) {
TreeNode root = null;
if(!str.equals("")){
String[] list = str.split(",");
//先建立根节点
root = new TreeNode(Integer.parseInt(list[0]));
Queue<TreeNode> queue = new LinkedList<TreeNode>();
queue.offer(root);//把需要插入左右节点的元素放在队列中管理,一旦左右子树建立之后就从队列中移除
int index = 1;
while(!queue.isEmpty() && index < list.length){
TreeNode temp = queue.poll();
if(!list[index].equals("#")){
TreeNode newLeft = new TreeNode(Integer.parseInt(list[index]));
temp.left = newLeft;
index ++;
queue.offer(newLeft);
}else
index ++;//所有的if都应该配备else,不然真的很容易出错误
if(index < list.length && !list[index].equals("#")){
TreeNode newRight = new TreeNode(Integer.parseInt(list[index]));
temp.right = newRight;
index ++;
queue.offer(newRight);
}else
index++;//所有的if都应该配备else,不然真的很容易出错误
}
}
return root;
}
}
JZ63
题目:
如何得到一个数据流中的中位数?如果从数据流中读出奇数个数值,那么中位数就是所有数值排序之后位于中间的数值。如果从数据流中读出偶数个数值,那么中位数就是所有数值排序之后中间两个数的平均值。我们使用Insert()方法读取数据流,使用GetMedian()方法获取当前读取数据的中位数。
思路:
用ArrayList存储数据,然后用冒泡排序即可
import java.util.*;
public class Solution {
ArrayList<Integer> arr=new ArrayList<>();
public void Insert(Integer num) {
arr.add(num);
}
public Double GetMedian() {
if(arr.size()==0)
return null;
int i,j,temp;
for(i=0;i<arr.size()-1;i++){
for(j=0;j<arr.size()-1-i;j++){
if(arr.get(j)>arr.get(j+1)){
temp=arr.get(j);
arr.set(j,arr.get(j+1));
arr.set(j+1,temp);
}
}
}
int index=arr.size()/2;
if(arr.size()%2==0){
double result=((double)arr.get(index)+(double)arr.get(index-1))/2;
return result;
}else{
return (double)arr.get(index);
}
}
}
总结:
double result=((double)arr.get(index)+(double)arr.get(index-1))/2; 在int和double类型转换时,需要注意将每个int转换为double再进行乘除法。
JZ65
题目:
思路:
采用递归的方法,注意判断好边界问题
public class Solution {
public boolean hasPath(char[] matrix, int rows, int cols, char[] str)
{
if(matrix==null||matrix.length==0)
return false;
int[] flag=new int[rows*cols];
for(int i=0;i<rows;i++){
for(int j=0;j<cols;j++){
if(help(i,j,0,matrix,str,rows,cols,flag))
return true;
}
}
return false;
}
public boolean help(int i,int j,int cur,char[] matrix,char[] str,int rows,int cols,int[] flag){
//cur为数组str的索引,flag记录该位置是否被访问
int index=i*cols+j;//matrix的索引
if(i>=0&&i<rows&&j>=0&&j<cols&&flag[index]==0){
if(matrix[index]==str[cur]){
cur++;
//str遍历完毕,可以找到该路径
if(cur>=str.length)
return true;
//该节点被访问过
flag[index]=1;
if(help(i-1,j,cur,matrix,str,rows,cols,flag)||
help(i+1,j,cur,matrix,str,rows,cols,flag)||
help(i,j-1,cur,matrix,str,rows,cols,flag)||
help(i,j+1,cur,matrix,str,rows,cols,flag)){
return true;
}
//该节点不符合条件,重新设置为未访问
flag[index]=0;
return false;
}
return false;
}
return false;
}
}
JZ66
题目:
地上有一个m行和n列的方格。一个机器人从坐标0,0的格子开始移动,每一次只能向左,右,上,下四个方向移动一格,但是不能进入行坐标和列坐标的数位之和大于k的格子。 例如,当k为18时,机器人能够进入方格(35,37),因为3+5+3+7 = 18。但是,它不能进入方格(35,38),因为3+5+3+8 = 19。请问该机器人能够达到多少个格子?
思路:
首先在某个节点处,要调用递归来决定某个位置的下一步去哪,此时有4个选择,每个选择都会进入下一个递归调用。当进入某个位置时,应当标记这个位置已访问过,避免之后又来到这里。在递归方法中,首先判断边界条件以及题目中所提的要求是否满足,都没问题,说明该位置可以访问,然后改变对应位置的标记。然后就是以该节点为中心,考虑下一步怎么走,本题就是4种走法,可以分开写,也可以一起写,由于本题是计数,所以就直接加在一起。然后return这些求和结果再+1,求和结果是下一步走的结果,而+1是本次访问此时的节点的次数。
public class Solution {
private int count=0;
public void helper(int i,int j,int rows,int cols,int[][] flag,int threshold){
//不符合条件就直接返回
if(i<0||i>=rows||j<0||j>=cols||flag[i][j]==1)return;
if(sum(i)+sum(j)>threshold){
flag[i][j]=1;
return;
}
flag[i][j]=1;
count++;
helper(i-1,j,rows,cols,flag,threshold);
helper(i+1,j,rows,cols,flag,threshold);
helper(i,j-1,rows,cols,flag,threshold);
helper(i,j+1,rows,cols,flag,threshold);
}
public int sum(int i){
int res=0;
while(i!=0){
res+=i%10;
i=i/10;
}
return res;
}
public int movingCount(int threshold, int rows, int cols)
{
int[][] flag=new int[rows][cols];
helper(0,0,rows,cols,flag,threshold);
return count;
}
}
JZ67
题目:
给你一根长度为n的绳子,请把绳子剪成整数长的m段(m、n都是整数,n>1并且m>1,m<=n),每段绳子的长度记为k[1],…,k[m]。请问k[1]x…xk[m]可能的最大乘积是多少?例如,当绳子的长度是8时,我们把它剪成长度分别为2、3、3的三段,此时得到的最大乘积是18。
思路:
这题目用动态规划。首先题目要求至少切一次。当target<=3时可以明确得出最大乘积,当target>3后,dp[n]=max(dp[n-i]*dp[i])。假设n为10,第一刀之后分为了4-6,而6也可能再分成2-4(6的最大是3-3,但过程中还是要比较2-4这种情况的),而上一步4-6中也需要求长度为4的问题的最大值,可见,各个子问题之间是有重叠的,所以可以先计算小问题,存储下每个小问题的结果,逐步往上,求得大问题的最优解
public class Solution {
public int cutRope(int target) {
if(target<2)
return 0;
if(target==2)
return 1;
if(target==3)
return 2;
int[]dp=new int[target+1];
dp[1]=1;
dp[2]=2;
dp[3]=3;
int max=0;
for(int i=4;i<=target;i++){
for(int j=1;j<=i/2;j++){
max=max>(dp[j]*dp[i-j])?max:(dp[j]*dp[i-j]);
}
dp[i]=max;
}
return dp[target];
}
}
总结:
后续对动态规划需要总结和练习