面试题25:二叉搜索树的后序遍历序列
输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果。如果是则输出Yes,否则输出No。假设输入的数组的任意两个数字都互不相同。
代码:
import java.util.Arrays;
public class Solution {
public boolean VerifySquenceOfBST(int [] sequence) {
if(sequence==null || sequence.length==0) return false;
int root = sequence[sequence.length-1];
int n=sequence.length-1;
for(int i=0;i<n;i++) {
if(sequence[i]==root) return false;
if(sequence[i]>root) {
n=i; //找到左右子树分割点
}
}
if(n<sequence.length-1) {
for(int i=n;i<sequence.length-1;i++) {
if(sequence[i]<=root) return false;
//判断后面的子树是否符合二叉搜素树的条件
}
}
if(n>0) { //左子树递归
VerifySquenceOfBST(Arrays.copyOfRange(sequence, 0, n));
}
if(n<sequence.length-1) { //右子树递归
VerifySquenceOfBST(Arrays.copyOfRange(sequence, n, sequence.length-1));
}
return true;
}
}
注意:这道题主要考察的是对二叉搜索树性质,记住了性质就能写出来!
知识点:
<1>二叉搜索树(BST):
* 要么是一棵空树
* 如果不为空,那么左子树节点的值都小于根节点的值,右子树节点的值都大于根节点的值
* 其左右子树也是二叉搜索树
面试题26:二叉树中和为某一值的路径
输入一颗二叉树和一个整数,打印出二叉树中结点值的和为输入整数的所有路径。路径定义为从树的根结点开始往下一直到叶结点所经过的结点形成一条路径。
代码:(大神的最简洁的代码)
public class Solution {
ArrayList<ArrayList<Integer>> a = new ArrayList<ArrayList<Integer>>();
ArrayList<Integer> list = new ArrayList<Integer>();
public ArrayList<ArrayList<Integer>> FindPath(TreeNode root,int target) {
if(root == null) return a;
list.add(root.val);
target -= root.val;
if(target == 0 && root.left==null && root.right==null) {
a.add(new ArrayList<Integer>(list));
..注意这里一定要是new,不然不会创建新的,代码会错!
}
FindPath(root.left,target);
FindPath(root.right,target);
list.remove(list.size()-1);//回退
return a;
}
}
知识点:
这道题主要考察的是二叉树的前序遍历算法和栈的结合
写完了发现对二叉树的前序遍历的理解还是不到位!这道题需要好好想!
/*
* 先序遍历二叉树(递归)
*/
public void PrintBinaryTreePreRecur(TreeNode root)
{
if (root!=null)
{
System.out.print(root.data);
PrintBinaryTreePreRecur(root.left);
PrintBinaryTreePreRecur(root.right);
}
}
面试题27:复杂链表的复制
输入一个复杂链表(每个节点中有节点值,以及两个指针,一个指向下一个节点,另一个特殊指针指向任意一个节点),返回结果为复制后复杂链表的head。(注意,输出结果中请不要返回参数中的节点引用,否则判题程序会直接返回空)
代码:
public class Solution {
public RandomListNode Clone(RandomListNode pHead)
{
if(pHead==null) return null;
RandomListNode p = pHead;
//第一次遍历,形成新链
while(p != null) {
RandomListNode n = new RandomListNode(p.label);
n.next = p.next;
p.next = n;
p = n.next;
}
RandomListNode p1 = pHead;
RandomListNode p2 = pHead.next;
//对random指针进行处理
while(p1 != null) {
if(p1.random != null) {
p1.next.random = p1.random.next;
}
p1 = p1.next.next;
}
//拆分
RandomListNode pp = pHead.next;
p2 = pHead.next;
p1 = pHead;
//下面这部分是在牛客上出错最多的!!!
while(p1 != null) {
p1.next = p1.next.next;
if(p2.next != null){
p2.next = p2.next.next;
}
p1 = p1.next;
p2 = p2.next;
}
return pp;
}
}
面试题28:二叉搜索树与双向链表
输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的双向链表。要求不能创建任何新的结点,只能调整树中结点指针的指向。
代码:
public class Solution {
TreeNode p = null;
TreeNode head = null;
public TreeNode Convert(TreeNode pRootOfTree) {
if(pRootOfTree == null) return null;
Convert(pRootOfTree.left);
if(p == null) {
p = pRootOfTree;
head = pRootOfTree;
}else {
p.right = pRootOfTree;
pRootOfTree.left = p;
p = pRootOfTree;
}
Convert(pRootOfTree.right);
return head; //这个位置必须是双向链表的第一个,否则报错
}
}
注意:
理论上这道题用递归是最简单的,这道题的主要分析点一个是中序遍历,另一个就是对递归中心状态的分析,这个中心状态要结合本题中的双向链表的特点来分析!
面试题29:字符串的排列
输入一个字符串,按字典序打印出该字符串中字符的所有排列。例如输入字符串abc,则打印出由字符a,b,c所能排列出来的所有字符串abc,acb,bac,bca,cab和cba。
输入描述:
输入一个字符串,长度不超过9(可能有字符重复),字符只包括大小写字母。
面试题30:数组中出现次数超过一半的数字
数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。例如输入一个长度为9的数组{1,2,3,2,2,2,5,4,2}。由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2。如果不存在则输出0。
代码 :
public class Solution {
public int MoreThanHalfNum_Solution(int [] array) {
if(array == null) return 0;
int count=1;
int num=array[0];
//找出这个可能出现的数字
for(int i=1;i<array.length;i++) {
if(count==0) {
count=1;
num=array[i];
}else if(num == array[i]) {
count+=1;
}else {
count-=1;
}
}
//对这个数字真的是不是进行验证
count=0;
for(int i=0;i<array.length;i++) {
if(array[i] == num) count++;
}
if(count<=array.length/2) {
return 0;
}else {
return num;
}
}
}
面试题31:最小的K个数
输入n个整数,找出其中最小的K个数。例如输入4,5,1,6,2,7,3,8这8个数字,则最小的4个数字是1,2,3,4,。
代码1:(使用快排)
import java.util.ArrayList;
import java.util.Arrays;
public class Solution {
public ArrayList<Integer> GetLeastNumbers_Solution(int [] input, int k) {
//使用快排算法
ArrayList<Integer> a = new ArrayList<Integer>();
if(input == null || k<=0 || k>input.length) return a;
Arrays.sort(input);
for(int i = 0;i<k;i++) {
a.add(input[i]);
}
return a;
}
}
代码2:使用分治
代码3:使用最大堆(大神代码)
import java.util.ArrayList;
import java.util.PriorityQueue;
import java.util.Comparator;
public class Solution {
public ArrayList<Integer> GetLeastNumbers_Solution(int[] input, int k) {
ArrayList<Integer> result = new ArrayList<Integer>();
int length = input.length;
if(k > length || k == 0){
return result;
}
PriorityQueue<Integer> maxHeap = new PriorityQueue<Integer>(k, new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return o2.compareTo(o1);
}
});
for (int i = 0; i < length; i++) {
if (maxHeap.size() != k) {
maxHeap.offer(input[i]);
} else if (maxHeap.peek() > input[i]) {
Integer temp = maxHeap.poll();
temp = null;
maxHeap.offer(input[i]);
}
}
for (Integer integer : maxHeap) {
result.add(integer);
}
return result;
}
}
代码4:使用冒泡
面试题32:连续子数组的最大和
HZ偶尔会拿些专业问题来忽悠那些非计算机专业的同学。今天测试组开完会后,他又发话了:在古老的一维模式识别中,常常需要计算连续子向量的最大和,当向量全为正数的时候,问题很好解决。但是,如果向量中包含负数,是否应该包含某个负数,并期望旁边的正数会弥补它呢?例如:{6,-3,-2,7,-15,1,2,2},连续子向量的最大和为8(从第0个开始,到第3个为止)。你会不会被他忽悠住?(子向量的长度至少是1)
代码:(不是动态规划)
public class Solution {
public int FindGreatestSumOfSubArray(int[] array) {
if(array == null) return 0;
int max=array[0];
int current=array[0];
for(int i=1;i<array.length;i++) {
if(current<0) {
current=array[i];
}else {
current += array[i];
}
if(current>max) {
max = current;
}
}
return max;
}
}
代码2:动态规划
面试题33:整数中1出现的次数(从1到n整数中1出现的次数)
求出1~13的整数中1出现的次数,并算出100~1300的整数中1出现的次数?为此他特别数了一下1~13中包含1的数字有1、10、11、12、13因此共出现6次,但是对于后面问题他就没辙了。ACMer希望你们帮帮他,并把问题更加普遍化,可以很快的求出任意非负整数区间中1出现的次数。
代码1:暴力算法
public class Solution {
public int NumberOf1Between1AndN_Solution(int n) {
if(n<=0) return 0;
int count=0;
for(int i=1;i<=n;i++) {
count+=NumberOf1(i);
}
return count;
}
public int NumberOf1(int n) {
int num=0;
while(n>=1) {
if(n%10==1) num+=1;
n /= 10;
}
return num;
}
}
代码2:新奇解法
注意:这道题有常规解法,也有新奇的解法!
面试题34:把数组排成最小的数
输入一个正整数数组,把数组里所有数字拼接起来排成一个数,打印能拼接出的所有数字中最小的一个。例如输入数组{3,32,321},则打印出这三个数字能排成的最小数字为321323。
代码:
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
public class Solution {
public String PrintMinNumber(int [] numbers) {
if(numbers==null) return null;
String [] s;
//将数字都转化为字符串
s = new String[numbers.length];
for(int i=0;i<numbers.length;i++) {
s[i] = ""+numbers[i];
}
//通过新的比较规则进行排序(注意:考虑比较的时候一定是两个两个的比较的)
Arrays.sort(s,new Comparator<String>() {
public int compare(String s1,String s2) {
String a = s1+s2;
String b = s2+s1;
return a.compareTo(b);
}
});
//将排序好的进行连接成一整个字符串
String a = "";
for(int i=0;i<s.length;i++) {
a = a+s[i];
}
return a;
}
}
注意: 这道题定义了新的比较规则,然后按照新的规则来进行排序的!
面试题35:丑数
把只包含因子2、3和5的数称作丑数(Ugly Number)。例如6、8都是丑数,但14不是,因为它包含因子7。 习惯上我们把1当做是第一个丑数。求按从小到大的顺序的第N个丑数。
代码1:这种也对,但是牛客提示超时
public int GetUglyNumber_Solution(int index) {
if(index <= 0) return 0;
int num=1;//要返回的第N个丑数
int p=1;//要一直往上增加的数
while(index>1) {
int shang=p;
while(shang%2==0 && shang>0) {
shang = shang/2;
}
while(shang%3==0 && shang>0) {
shang = shang/3;
}
while(shang%5==0 && shang>0) {
shang = shang/5;
}
if(shang == 1 ) {
index-=1;
num = p;
}
p++;
}
return num;
代码2:
知识点:
丑数:首先除2,直到不能整除为止,然后除5到不能整除为止,然后除3直到不能整除为止。最终判断剩余的数字是否为1,如果是1则为丑数,否则不是丑数。