剑指offer记录

11 篇文章 0 订阅

二刷

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];
    }
}

总结:

后续对动态规划需要总结和练习

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值