7.输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建二叉树并返回。
思路:先找出根节点,然后利用递归方法构造二叉树
public static class TreeNode { //构建二叉树的类
int val;
TreeNode left;
TreeNode right;
TreeNode(int x) { val = x; }
}
public TreeNode reConstructBinaryTree(int [] pre,int [] in) {
if (pre == null || in == null) {
return null;
}//异常处理:防止数组为空
if (pre.length == 0 || in.length == 0) {
return null;
}//异常处理:防止数组长度为0
if (pre.length != in.length) {
return null;
}//异常处理:防止两数组长度不等
TreeNode root = new TreeNode(pre[0]);//实例化二叉树,并在根节点放入1
for (int i = 0; i < pre.length; i++) {
if (pre[0] == in[i]) {//寻找中序遍历中根节点
root.left = reConstructBinaryTree(
Arrays.copyOfRange(pre,1,i+1),Arrays.copyOfRange(in,0,i));
//递归运算并将根节点的左节点抽出放入函数reConstructBinaryTree
root.right = reConstructBinaryTree(
Arrays.copyOfRange(pre,i+1,pre.length),Arrays.copyOfRange(in,i+1,in.length));
//递归运算并将根节点的右2节点抽出放入函数reConstructBinaryTree
}
}
return root;
}
8.略
9.用两个栈来实现一个队列,完成队列的Push和Pop操作。 队列中的元素为int类型。
思路:一个栈压入元素,而另一个栈作为缓冲,将栈1的元素出栈后压入栈2中。也可以将栈1中的最后一个元素直接出栈,而不用压入栈2中再出栈。
public void push(int node) {
stack1.push(node);
}//将元素压入stack1
public int pop() throws Exception {
if (stack1.isEmpty() && stack2.isEmpty()) {
throw new Exception("栈为空!");
}//异常处理
if (stack2.isEmpty()) {
while(!stack1.isEmpty()) {
stack2.push(stack1.pop());//对stack1进行循环,将stack1中弹出元素压入stack2中
}
}
return stack2.pop();//从stack2中弹出元素
}
10.现在要求输入一个整数n,请你输出斐波那契数列的第n项
思路:用递归的方法实现
public long fibonacci(int n) {
if(n<=0)
return 0;
if(n==1)
return 1;
return fibonacci(n-1)+fibonacci(n-2);
}
思路:用循环的方法实现
public class QuickSort {
public static void quickSort(int[] arr,int low,int high){
int i,j,temp,t;
if(low>high){
return;
}
i=low;
j=high;
//temp就是基准位
temp = arr[low];
while (i<j) {
//先看右边,依次往左递减
while (temp<=arr[j]&&i<j) {
j--;
}
//再看左边,依次往右递增
while (temp>=arr[i]&&i<j) {
i++;
}
//如果满足条件则交换
if (i<j) {
t = arr[j];
arr[j] = arr[i];
arr[i] = t;
}
}
//最后将基准位与i和j相等位置的数字交换
arr[low] = arr[i];
arr[i] = temp;
//递归调用左半数组
quickSort(arr, low, j-1);
//递归调用右半数组
quickSort(arr, j+1, high);
}
public static void main(String[] args){
int[] arr = {10,7,2,4,7,62,3,4,2,1,8,9,19};
quickSort(arr, 0, arr.length-1);
for (int i = 0; i < arr.length; i++) {
System.out.println(arr[i]);
}
}
}
11.1把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。 输入一个递增排序的数组的一个旋转,输出旋转数组的最小元素。 例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组的最小值为1。 NOTE:给出的所有元素都大于0,若数组大小为0,请返回0
思路:利用二分法,找到中间的数,然后和最左边的值进行比较,若大于最左边的数,则最左边从mid开始,若小于最右边值,则最右边从mid开始。若左中右三值相等,则取mid前后值中较小的数。
public int minNumberInRotateArray(int [] array) {
if (array == null || array.length == 0)
return 0;
int left = 0;
int right = array.length - 1;
int mid = 0;
while (array[left] >= array[right]) {
if(right - left <= 1) {
mid = right;
break;
}
mid = (left + right)/2;
if(array[left]>=array[mid])
left=mid;
else if(array[mid]<=array[right])
right=mid;
}
return array[mid];
}
11.2把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。 输入一个非递增排序的数组的一个旋转,输出旋转数组的最小元素。 例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组的最小值为1。 NOTE:给出的所有元素都大于0,若数组大小为0,请返回0
思路:利用二分法,找到中间的数,然后和最左边的值进行比较,若大于最左边的数,则最左边从mid开始,若小于最右边值,则最右边从mid开始。若左中右三值相等,则取mid前后值中较小的数。
public int minNumberInRotateArray(int [] array) {
if (array == null || array.length == 0)
return 0;
int left = 0;
int right = array.length - 1;
int mid = 0;
while (array[left] >= array[right]) {
if(right - left <= 1) {
mid = right;
break;
}
mid = (left + right)/2;
//如果下表为left,right,mid指向的数字相等,则只能顺序查找
if(array[left]==array[right]&&array[mid]==array[left])
return minInOrder(array,left,right)
if(array[left]>=array[mid])
left=mid;
else if(array[mid]<=array[right])
right=mid;
}
return array[mid];
}
public minInOrder(int [] array,left,right){
int result=array[left];
for(int i=left+1;i<=right;i++){
if(result>array[i])
result=array[i]
}
}
12.请设计一个函数,用来判断在一个矩阵中是否存在一条包含某字符串所有字符的路径。路径可以从矩阵中的任意一格开始,每一步可以在矩阵中向左、右、上、下移动一格。如果一条路径经过了矩阵的某一格,那么该路径不能再次进入该格子。例如,在下面的3×4的矩阵中包含一条字符串“bfce”的路径(路径中的字母用加粗标出)。
[[“a”,“b”,“c”,“e”],
[“s”,“f”,“c”,“s”],
[“a”,“d”,“e”,“e”]]
思路:回溯法、递归实现
首先,在矩阵中任选一个格子作为路径的起点。
由于回朔法的递归特性,路径可以被看成一个栈。当在矩阵中定位了路径中前n个字符的位置之后,在与第n个字符对应的格子的周围都没有找到第n+1个字符,这个时候只要在路径上回到第n-1个字符,重新定位第n个字符。一直重复这个过程,直到路径字符串上所有字符都在矩阵中找到合适的位置。
由于路径不能重复进入矩阵的格子,还需要定义和字符矩阵大小一样的布尔值矩阵,用来标识路径是否已经进入每个格子。
public class problem12 {
public boolean exist(char[][] board,String word){
char[] words= word.toCharArray();//将字符串转换为字符数组
boolean res = false;
for(int i=0;i<board.length;i++){
for (int j = 0; j <board[0].length ; j++) {//在board中寻找起点
res = dfs(board,words,i,j,0);//从起点开始寻找
if(res==true)
return res;//存在路径
}
}
return res;//不存在
}
private boolean dfs(char[][] board, char[] words, int i, int j, int k) {
if(i<0 || i>=board.length || j<0 || j>=board[0].length||board[i][j]!=words[k])//遇到矩阵边界或不符合字符串返回false
return false;
if(k==words.length-1)
return true;//到达字符串末尾,返回true
board[i][j]='\0';
boolean res = dfs(board,words,i+1,j,k+1) || dfs(board,words,i-1,j,k+1) ||
dfs(board,words,i,j+1,k+1) || dfs(board,words,i,j-1,k+1);
board[i][j]=words[k];
return res;
}
}
13.地上有一个m行n列的方格,从坐标 [0,0] 到坐标 [m-1,n-1] 。一个机器人从坐标 [0, 0]的格子开始移动,它每次可以向左、右、上、下移动一格(不能移动到方格外),也不能进入行坐标和列坐标的数位之和大于k的格子。例如,当k为18时,机器人能够进入方格 [35, 37] ,因为3+5+3+7=18。但它不能进入方格 [35, 38],因为3+5+3+8=19。请问该机器人能够到达多少个格子?
思路:
class Solution {
int sums(int x )
{
int s=0;
while(x!=0){
s+=x%10;
x=x/10;
}
return s;
}//计算x各个位数之和
int k,m,n;
boolean[][] visited;//比特二维数组
public int movingCount(int m,int n,int k){
this.m=m;this.n=n;this.k=k;
this.visited=new boolean[m][n];//定位二维数组大小
return dfs(0,0);
}
private int dfs(int i, int j ){
if(i>=m || j>=n || k<(sums(i)+sums(j)) || visited[i][j])
return 0;
visited[i][j]=true;//i,j可走
return 1+dfs(i+1,j)+dfs(i,j+1);//递归运算
}
}
import java.util.LinkedList;
public class problem13 {
int sums(int x )
{
int s=0;
while(x!=0){
s+=x%10;
x=x/10;
}
return s;
}//返回各个位数相加之和
public int movingCount(int m,int n,int k){
boolean[][] visited=new boolean[m][n];//初始化二维矩阵大小
int res =0;
LinkedList<int[]> queue = new LinkedList<>();
queue.add(new int[]{0,0});
while(!queue.isEmpty()){//检验是否为空
int[] x = queue.poll();//检索链表的第一个元素,并从列表中删除第一个元素。
int i=x[0],j=x[1];
if(i>=m||j>=n||k<(sums(i)+sums(j))||visited[i][j])
continue;//不符合条件进入下一循环
visited[i][j]=true;//{i,j}可走
res++;//可走格数加一
queue.add(new int[]{i+1,j});
queue.add(new int[]{i,j+1});
}
return res;//返回总数
}
}
14.给你一根长度为 n 的绳子,请把绳子剪成整数长度的 m 段(m、n都是整数,n>1并且m>1),每段绳子的长度记为 k[0],k[1]...k[m-1] 。请问 k[0]*k[1]*...*k[m-1] 可能的最大乘积是多少?例如,当绳子的长度是8时,我们把它剪成长度分别为2、3、3的三段,此时得到的最大乘积是18。
思路:动态规划
class Solution {
public int cuttingRope(int n) {
int[] dp = new int[n + 1];//初始化一个n+1大小的数组存放每一段绳子的大小
dp[2] = 1;//如果绳子长度为2,结果为1
for(int i = 3; i < n + 1; i++){//剪的第几刀
for(int j = 2; j < i; j++){//第i刀剪出绳子的长度
dp[i] = Math.max(dp[i], Math.max(j * (i - j), j * dp[i - j]));//不剪和剪j孰大
}
}
return dp[n];
}
}