目录
34 第一个只出现一次的字符
在一个字符串(0<=字符串长度<=10000,全部由字母组成)中找到第一个只出现一次的字符,并返回它的位置, 如果没有则返回 -1(需要区分大小写).
public class Solution {
public int FirstNotRepeatingChar(String str) {
if(str.equals(""))
return -1;
int [] temp = new int[256];
int index = 1;
char [] strArray = str.toCharArray();
for(int i=0;i<strArray.length;i++)
{
if(temp[(int)strArray[i]] == 0)
{
temp[(int)strArray[i]] = index;
index++;
}else{
temp[(int)strArray[i]] = -1;
}
}//这个循环就是遍历一遍,找到出现一次的字符
//只要index大于0就是出现一次的字符
int minIndex = Integer.MAX_VALUE;
char ch = '1';
for(int i=0;i<temp.length;i++)
{
if(temp[i] > 0)
{
if(temp[i] < minIndex)
{//找最小的index对应的字符
minIndex = temp[i];
ch = (char)i;
}
}
}
int result = -1;
for(int i=0;i<strArray.length;i++)
{//去找这个字符的下标!
if(strArray[i] == ch)
return i;
}
return -1;
}
}
35 数组中的逆序对
在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数P。并将P对1000000007取模的结果输出。 即输出P%1000000007
public class Solution {
public static int InversePairs(int [] array) {
if(array==null||array.length==0)
{
return 0;
}
int[] copy = new int[array.length];
for(int i=0;i<array.length;i++)
{
copy[i] = array[i];
}
int count = InversePairsCore(array,copy,0,array.length-1);//数值过大求余
return count;
}
private static int InversePairsCore(int[] array,int[] copy,int low,int high)
{
if(low==high)
{
return 0;
}
int mid = (low+high)>>1;
int leftCount = InversePairsCore(array,copy,low,mid)%1000000007;
int rightCount = InversePairsCore(array,copy,mid+1,high)%1000000007;
int count = 0;
int i=mid;
int j=high;
int locCopy = high;
while(i>=low&&j>mid)
{
if(array[i]>array[j])
{
count += j-mid;
copy[locCopy--] = array[i--];
if(count>=1000000007)//数值过大求余
{
count%=1000000007;
}
}
else
{
copy[locCopy--] = array[j--];
}
}
for(;i>=low;i--)
{
copy[locCopy--]=array[i];
}
for(;j>mid;j--)
{
copy[locCopy--]=array[j];
}
for(int s=low;s<=high;s++)
{
array[s] = copy[s];
}
return (leftCount+rightCount+count)%1000000007;
}
}
36 两个链表的第一个公共结点
输入两个链表,找出它们的第一个公共结点。
/*
public class ListNode {
int val;
ListNode next = null;
ListNode(int val) {
this.val = val;
}
}*/
public class Solution {
public ListNode FindFirstCommonNode(ListNode pHead1, ListNode pHead2) {
if(pHead1 == null || pHead2 == null)
return null;
int length1 = 0;
int length2 = 0;
ListNode p1 = pHead1,p2 = pHead2;
while(p1 != null)
{
length1++;
p1 = p1.next;
}
while(p2 != null)
{
length2++;
p2 = p2.next;
}//分别求两个链表长度
int cha = 0;
if(length1 > length2)
{//求长度差,长的先走长度差个单位
cha = length1 - length2;
p1 = pHead1;
p2 = pHead2;
for(int i=0;i<cha;i++)
p1 = p1.next;
}else{
cha = length2 - length1;
p2 = pHead2;
p1 = pHead1;
for(int i=0;i<cha;i++)
p2 = p2.next;
}
while(p1 != p2)
{//找第一个相同的节点
p1 = p1.next;
p2 = p2.next;
}
return p1;
}
}
37 数字在排序数组中出现的次数
统计一个数字在排序数组中出现的次数。
public class Solution {
public int GetNumberOfK(int [] array , int k) {
int leftIndex = -1,start=0,end=array.length-1,rightIndex=-1;
while(start <= end)
{
int mid = (start+end)/2;
if(array[mid] > k)
{
end = mid-1;
}else if(array[mid] < k){
start = mid+1;
}else{
leftIndex = mid;
end = mid-1;
}
}
start = 0;
end = array.length-1;
while(start <= end)
{
int mid = (start+end)/2;
if(array[mid] > k)
{
end = mid-1;
}else if(array[mid] < k){
start = mid+1;
}else{
rightIndex = mid;
start = mid+1;
}
}
if(array.length == 0 || rightIndex == -1)
return 0;
return rightIndex-leftIndex+1;
}
}
38 二叉树的深度
输入一棵二叉树,求该树的深度。从根结点到叶结点依次经过的结点(含根、叶结点)形成树的一条路径,最长路径的长度为树的深度。
public class Solution {
public int TreeDepth(TreeNode root) {
if (root == null)
return 0;
if (root != null && root.left == null && root.right == null)
return 1;
return TreeDepth(root.left)>TreeDepth(root.right)?TreeDepth(root.left)+1:TreeDepth(root.right)+1;
}
}
39 平衡二叉树
输入一棵二叉树,判断该二叉树是否是平衡二叉树。
public class Solution {
public boolean IsBalanced_Solution(TreeNode root) {
if( root == null) { //一棵空树就是平衡二叉树
return true;
}
if( Math.abs(getDepth(root.left) - getDepth(root.right)) <= 1 ) {
//满足左右子树高度差小于等于1,那就接着判断左右子树是不是二叉树
return (IsBalanced_Solution(root.left) && IsBalanced_Solution(root.right));
} else {
//不满足左右子树高度差小于等于1,那这棵树肯定不是平衡二叉树啦
return false;
}
}
public int getDepth(TreeNode root) {
if( root == null ) return 0;
int left = getDepth(root.left);
int right = getDepth(root.right);
return ( left > right ? left : right ) + 1;//树的高度怎么计算就不用我讲了吧
}
}
40 数组中只出现一次的数字
一个整型数组里除了两个数字之外,其他的数字都出现了偶数次。请写程序找出这两个只出现一次的数字。
//num1,num2分别为长度为1的数组。传出参数
//将num1[0],num2[0]设置为返回结果
public class Solution {
public void FindNumsAppearOnce(int [] array,int num1[] , int num2[]) {
int temp = 0;
for (int i = 0; i < array.length; i++) {
temp = temp ^ array[i];
}
int index = findOne (temp);
num1[0] = 0;
num2[0] = 0;
for (int i = 0; i < array.length; i++) {
if(IsBit1(array[i], index)){
num1[0] ^= array[i];
} else {
num2[0] ^= array[i];
}
}
}
private int findOne(int number)
{
int index = 0;
while((number & 1) == 0)
{
index++;
number = number >> 1;
}
return index;
}
private boolean IsBit1(int number,int index)
{
number = number >> index;
if((number & 1) == 0)
return false;
return true;
}
}
41 和为S的连续正数序列
小明很喜欢数学,有一天他在做数学作业时,要求计算出9~16的和,他马上就写出了正确答案是100。但是他并不满足于此,他在想究竟有多少种连续的正数序列的和为100(至少包括两个数)。没多久,他就得到另一组连续正数和为100的序列:18,19,20,21,22。现在把问题交给你,你能不能也很快的找出所有和为S的连续正数序列? Good Luck!
import java.util.ArrayList;
import java.util.LinkedList;
public class Solution {
public ArrayList<ArrayList<Integer>> FindContinuousSequence(int sum) {
ArrayList<ArrayList<Integer>> res = new ArrayList();
if(sum <= 1){
return res;
}
LinkedList<Integer> queue = new LinkedList();
int n = 1, halfSum = (sum >> 1) + 1, queueSum = 0;
while(n <= halfSum){
queue.addLast(n);
queueSum += n;
if(queueSum > sum){
while(queueSum > sum){
queueSum -= queue.pollFirst();
}
}
if(queueSum == sum){
ArrayList<Integer> one = new ArrayList();
one.addAll(queue);
res.add(one);
queueSum -= queue.pollFirst();
}
n++;
}
return res;
}
}
42 和为S的两个数字
输入一个递增排序的数组和一个数字S,在数组中查找两个数,使得他们的和正好是S,如果有多对数字的和等于S,输出两个数的乘积最小的。
import java.util.ArrayList;
public class Solution {
public ArrayList<Integer> FindNumbersWithSum(int [] array, int sum){
ArrayList<Integer> resultList = new ArrayList<>();
if(array.length <= 1)
return resultList;
for(int i=0,j=array.length-1;i<j;)
{
if(array[i] + array[j] == sum)
{
resultList.add(array[i]);
resultList.add(array[j]);
return resultList;
//找到直接返回
}else if(array[i] + array[j] > sum)
{
//和已经大于目标值了,所以大数要减小!
j--;
}else{
//和小于目标值,所以小数要表大!
i++;
}
}
return resultList;
}
}
43 左旋转字符串
汇编语言中有一种移位指令叫做循环左移(ROL),现在有个简单的任务,就是用字符串模拟这个指令的运算结果。对于一个给定的字符序列S,请你把其循环左移K位后的序列输出。例如,字符序列S=”abcXYZdef”,要求输出循环左移3位后的结果,即“XYZdefabc”。是不是很简单?OK,搞定它!
public class Solution {
public String LeftRotateString(String str,int n) {
if (str == null || str.equals(""))
return "";
n = n % str.length();
char [] strA = str.toCharArray();
reverse(strA, 0, str.length() - 1);
reverse(strA, 0, str.length() - n - 1);
reverse(strA, str.length() - n, str.length() - 1);
return String.valueOf(strA);
}
public void reverse(char [] strA, int start, int end) {
while(start < end) {
char ch = strA[start];
strA[start] = strA[end];
strA[end] = ch;
start ++;
end --;
}
}
}
44 翻转单词顺序列
牛客最近来了一个新员工Fish,每天早晨总是会拿着一本英文杂志,写些句子在本子上。同事Cat对Fish写的内容颇感兴趣,有一天他向Fish借来翻看,但却读不懂它的意思。例如,“student. a am I”。后来才意识到,这家伙原来把句子单词的顺序翻转了,正确的句子应该是“I am a student.”。Cat对一一的翻转这些单词顺序可不在行,你能帮助他么?
public class Solution {
public String ReverseSentence(String str) {
if(str == null || str == "")
return str;
char[] strA = str.toCharArray();
reverse(strA, 0, strA.length - 1);
int begin = 0;
for(int i = 0; i < strA.length; i++) {
if(strA[i] == ' ') {
reverse(strA, begin, i - 1);
begin = i + 1;
}
}
if (begin < strA.length - 1){
reverse(strA, begin, strA.length - 1);
}
return String.valueOf(strA);
}
private void reverse(char [] str, int begin, int end) {
while (begin < end) {
char temp = str[begin];
str[begin] = str[end];
str[end] = temp;
begin ++;
end --;
}
}
}
45 扑克牌顺子
LL今天心情特别好,因为他去买了一副扑克牌,发现里面居然有2个大王,2个小王(一副牌原本是54张^_^)...他随机从中抽出了5张牌,想测测自己的手气,看看能不能抽到顺子,如果抽到的话,他决定去买体育彩票,嘿嘿!!“红心A,黑桃3,小王,大王,方片5”,“Oh My God!”不是顺子.....LL不高兴了,他想了想,决定大\小 王可以看成任何数字,并且A看作1,J为11,Q为12,K为13。上面的5张牌就可以变成“1,2,3,4,5”(大小王分别看作2和4),“So Lucky!”。LL决定去买体育彩票啦。 现在,要求你使用这幅牌模拟上面的过程,然后告诉我们LL的运气如何, 如果牌能组成顺子就输出true,否则就输出false。为了方便起见,你可以认为大小王是0。
import java.util.Arrays;
public class Solution {
public boolean isContinuous(int [] numbers) {
if (numbers.length <= 4)
return false;
Arrays.sort(numbers);
int numberZero = 0;
int numberNeed = 0;
for(int i = 0; i < numbers.length; i++) {
if (numbers[i] == 0) {
numberZero ++;
} else {
if(i < (numbers.length - 1)) {
if (numbers[i] == numbers[i + 1])
return false;
numberNeed += (numbers[i + 1] - numbers[i] - 1);
}
}
}
return numberZero >= numberNeed;
}
}
46 孩子们的游戏(圆圈中最后剩下的数)
每年六一儿童节,牛客都会准备一些小礼物去看望孤儿院的小朋友,今年亦是如此。HF作为牛客的资深元老,自然也准备了一些小游戏。其中,有个游戏是这样的:首先,让小朋友们围成一个大圈。然后,他随机指定一个数m,让编号为0的小朋友开始报数。每次喊到m-1的那个小朋友要出列唱首歌,然后可以在礼品箱中任意的挑选礼物,并且不再回到圈中,从他的下一个小朋友开始,继续0...m-1报数....这样下去....直到剩下最后一个小朋友,可以不用表演,并且拿到牛客名贵的“名侦探柯南”典藏版(名额有限哦!!^_^)。请你试着想下,哪个小朋友会得到这份礼品呢?(注:小朋友的编号是从0到n-1)
import java.util.*;
public class Solution {
public int LastRemaining_Solution(int n, int m) {
LinkedList<Integer> list = new LinkedList<>();
for(int i = 0; i < n; i++) {
list.add(i);
}
int a = 0;
while(list.size() > 1) {
a = (a + m - 1) % list.size();
list.remove(a);
}
if (list.size() == 1) {
return list.get(0);
}
return -1;
}
}
47 求1+2+3+…+n
求1+2+3+...+n,要求不能使用乘除法、for、while、if、else、switch、case等关键字及条件判断语句(A?B:C)。
public class Solution {
public int Sum_Solution(int n) {
int sum = n;
//短路与,当n小于0的时候,就不执行后面的代码了
boolean ans = (n>0)&&((sum+=Sum_Solution(n-1))>0);
return sum;
}
}
48 不用加减乘除做加法
写一个函数,求两个整数之和,要求在函数体内不得使用+、-、*、/四则运算符号。
public class Solution {
public int Add(int num1,int num2) {
int sum = 0;
int carry = 0;
do {
sum = num1 ^ num2;
carry = num1 & num2;
if (carry != 0)
carry = carry << 1;
num1 = sum;
num2 = carry;
} while(carry != 0);
return sum;
}
}
49 把字符串转换成整数
将一个字符串转换成一个整数(实现Integer.valueOf(string)的功能,但是string不符合数字要求时返回0),要求不能使用字符串转换整数的库函数。 数值为0或者字符串不是一个合法的数值则返回0。
public class Solution {
public int StrToInt(String str) {
if(str == null || str == "" || str.equals("+") || str.equals("-"))
return 0;
int flag = 0;
long sum = 0;
char [] strA = str.toCharArray();
for(int i = 0; i < strA.length; i++) {
if(strA[0] == '-' && i == 0){
flag = 1;
continue;
}
if(strA[0] == '+' && i == 0){
continue;
}
if(!judge(strA[i]))
return 0;
sum = sum * 10 + strA[i] - '0';
}
if (flag == 1) {
sum = sum * (-1);
if (sum < Integer.MIN_VALUE)
return 0;
return (int)sum;
}
if (sum > Integer.MAX_VALUE)
return 0;
return (int)sum;
}
public boolean judge(char ch) {
int number = ch - '0';
if(number >= 0 && number <= 9) {
return true;
}
return false;
}
}
50 数组中重复的数字
在一个长度为n的数组里的所有数字都在0到n-1的范围内。 数组中某些数字是重复的,但不知道有几个数字是重复的。也不知道每个数字重复几次。请找出数组中任意一个重复的数字。 例如,如果输入长度为7的数组{2,3,1,0,2,5,3},那么对应的输出是第一个重复的数字2。
public class Solution {
// Parameters:
// numbers: an array of integers
// length: the length of array numbers
// duplication: (Output) the duplicated number in the array number,length of duplication array is 1,so using duplication[0] = ? in implementation;
// Here duplication like pointor in C/C++, duplication[0] equal *duplication in C/C++
// 这里要特别注意~返回任意重复的一个,赋值duplication[0]
// Return value: true if the input is valid, and there are some duplications in the array number
// otherwise false
public boolean duplicate(int numbers[], int length, int[] duplication) {
if (numbers == null || length <= 0)
return false;
// 必须保证数组中的元素都在0到n-1之间
for (int i = 0; i < length; i++)
if (numbers[i] < 0 || numbers[i] > length)
return false;
int[] count = new int[length];
for (int i = 0; i < length; i++) {
count[i] = 0;
}
for (int i = 0; i < length; i++) {
if (count[numbers[i]] == 1) {
duplication[0] = numbers[i];
return true;
}
count[numbers[i]]++;
}
return false;
}
}
51 构建乘积数组
给定一个数组A[0,1,...,n-1],请构建一个数组B[0,1,...,n-1],其中B中的元素B[i]=A[0]*A[1]*...*A[i-1]*A[i+1]*...*A[n-1]。不能使用除法。
import java.util.ArrayList;
public class Solution {
public static int[] multiply(int[] A) {
if (A == null || A.length <= 0) {
return null;
}
int[] c = new int[A.length];
int[] d = new int[A.length];
int[] b = new int[A.length];
d[0] = 1; // 计算D
for (int i = 1; i < A.length; i++) {
d[i] = d[i-1] * A[i-1];
}
c[A.length-1] = 1; // 计算C
for (int j = A.length-1; j > 0; j--) {
c[j-1] = c[j] * A[j];
}
// 计算B
for (int i = 0; i < A.length; i++) {
b[i] = d[i]*c[i];
}
return b;
}
}
52 正则表达式匹配
请实现一个函数用来匹配包括'.'和'*'的正则表达式。模式中的字符'.'表示任意一个字符,而'*'表示它前面的字符可以出现任意次(包含0次)。 在本题中,匹配是指字符串的所有字符匹配整个模式。例如,字符串"aaa"与模式"a.a"和"ab*ac*a"匹配,但是与"aa.a"和"ab*a"均不匹配
public class Solution {
public boolean match(char[] str, char[] pattern)
{
if(str==null||pattern==null) return false;
return matchCore(str,0,pattern,0);
}
public boolean matchCore(char[] str,int s, char[] pattern,int p) {
if(str.length<=s&&pattern.length<=p)
return true;//都匹配完了
if(str.length>s&&pattern.length<=p)
return false;//模式完了,字符串还有
//模式串a*a没结束,匹配串可结束可不结束
if(p+1<pattern.length&&pattern[p+1]=='*'){//当前pattern的下一个是*号时
//字符串完了
if(s>=str.length) return matchCore(str, s, pattern, p+2);
else{
if(pattern[p]==str[s]||pattern[p]=='.'){
//当前位置匹配完成,移动到下一个模式串
return matchCore(str,s+1, pattern,p+2)
||matchCore(str,s+1, pattern,p)
||matchCore(str,s, pattern,p+2);
}else
return matchCore(str, s, pattern, p+2);
}
}
//当前pattern的下一个不是*时候
if(s>=str.length) return false;
else{
if(str[s]==pattern[p]||pattern[p]=='.')
return matchCore(str, s+1, pattern, p+1);
}
return false;
}
}
53 表示数值的字符串
请实现一个函数用来判断字符串是否表示数值(包括整数和小数)。例如,字符串"+100","5e2","-123","3.1416"和"-1E-16"都表示数值。 但是"12e","1a3.14","1.2.3","+-5"和"12e+4.3"都不是。
public class Solution {
public boolean isNumeric(char[] str) {
if (str == null || str.length == 0)
return false;
int[] index = new int[1];
index[0] = 0; // 用于记录当前字符位置
// 先判断A
boolean isNumeric; //用于记录是否满足条件
isNumeric = isInteger(str, index);
// 判断B
if (index[0] < str.length && (str[index[0]] == '.')) {
index[0]++;
isNumeric = isUnsignedInteger(str, index) || isNumeric; // .B和A.和A.B形式均可以
}
// 判断e后面的A
if (index[0] < str.length && (str[index[0]] == 'e' || str[index[0]] == 'E')) {
index[0]++;
isNumeric = isInteger(str, index) && isNumeric;
}
if (isNumeric && index[0] == str.length)
return true;
else
return false;
}
private boolean isInteger(char[] str, int[] index) { // 用int[]才能传值,int的话需要定义index为全局变量
if (index[0] < str.length && (str[index[0]] == '+' || str[index[0]] == '-'))
index[0]++;
return isUnsignedInteger(str, index);
}
private boolean isUnsignedInteger(char[] str, int[] index) {
int start = index[0];
while (index[0] < str.length && (str[index[0]] - '0' <= 9 && str[index[0]] - '0' >= 0))
index[0]++;
if (index[0] > start)
return true;
else
return false;
}
}
54 字符流中第一个不重复的字符
请实现一个函数用来找出字符流中第一个只出现一次的字符。例如,当从字符流中只读出前两个字符"go"时,第一个只出现一次的字符是"g"。当从该字符流中读出前六个字符“google"时,第一个只出现一次的字符是"l"。
public class Solution {
//Insert one char from stringstream
int[] charArray = new int[256];
int index = 1;
public void Insert(char ch)
{
if(charArray[(int)ch] == 0){
charArray[(int)ch] = index;
index++;
} else {
charArray[(int)ch] = -1;
}
}
//return the first appearence once char in current stringstream
public char FirstAppearingOnce()
{
char result = '#';
int min = Integer.MAX_VALUE;
for(int i = 0; i < 256; i++) {
if(charArray[i] > 0) {
if(min > charArray[i]) {
min = charArray[i];
result = (char)i;
}
}
}
return result;
}
}
55 链表中环的入口结点
给一个链表,若其中包含环,请找出该链表的环的入口结点,否则,输出null。
https://blog.youkuaiyun.com/sniperken/article/details/53870463
/*
public class ListNode {
int val;
ListNode next = null;
ListNode(int val) {
this.val = val;
}
}
*/
public class Solution
{
public ListNode EntryNodeOfLoop(ListNode pHead)
{
if(pHead == null || pHead.next == null)
return null;
ListNode fast = pHead;//快指针每次走两步
ListNode slow = pHead;//每次走一步
while(fast!=null && fast.next !=null)//因为fast每次要走两步,所有需要判断fast的下一个是否为空
{
slow = slow.next;
fast = fast.next.next;
//判断是否相遇 相遇后让快指针从头开始走,每次都是走一步,第二次相遇的节点就是环的入口
if(fast.val == slow.val)
{
fast = pHead;
while(fast.val != slow.val)
{
fast = fast.next;
slow = slow.next;
}
}
if(fast.val == slow.val)
{
return slow;
}
}
return null;//要是没有相遇,此链表没有环返回空
}
}
56 删除链表中重复的结点
在一个排序的链表中,存在重复的结点,请删除该链表中重复的结点,重复的结点不保留,返回链表头指针。 例如,链表1->2->3->3->4->4->5 处理后为 1->2->5
/*
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;
ListNode node = new ListNode(Integer.MIN_VALUE);
node.next = pHead;
ListNode pre = node, p = pHead;
boolean deleteMode = false;
while(p != null) {
if(p.next != null && p.next.val == p.val) {
p.next = p.next.next;
deleteMode = true;
}else if(deleteMode) {
pre.next = p.next;
p = pre.next;
deleteMode = false;
} else {
pre = p;
p = p.next;
}
}
return node.next;
}
}
57 二叉树的下一个结点
给定一个二叉树和其中的一个结点,请找出中序遍历顺序的下一个结点并且返回。注意,树中的结点不仅包含左右子结点,同时包含指向父结点的指针。
public class Solution {
public TreeLinkNode GetNext(TreeLinkNode pNode)
{
if(pNode == null)
return null;
if(pNode.right != null){
TreeLinkNode temp = pNode.right;
while(temp.left != null)
temp = temp.left;
return temp;
}
TreeLinkNode temp = pNode.next;
TreeLinkNode pre = pNode;
while(temp != null) {
if(temp.left == pre)
return temp;
pre = temp;
temp = temp.next;
}
return temp;
}
}
58 对称的二叉树
请实现一个函数,用来判断一颗二叉树是不是对称的。注意,如果一个二叉树同此二叉树的镜像是同样的,定义其为对称的。
public class Solution {
boolean isSymmetrical(TreeNode pRoot)
{
return judge(pRoot,pRoot);
}
boolean judge(TreeNode pRoot1,TreeNode pRoot2)
{
if(pRoot1 == null && pRoot2 == null)
return true;
//左右子树都是null,是true
if(pRoot1 == null || pRoot2 == null)
return false;
//左右子树一个为null一个不为空,那么肯定不是对称的
if(pRoot1.left != null && pRoot2.right != null && pRoot1.left.val != pRoot2.right.val)
return false;
//左右子树不为null,但val值不相等,不对称
if(pRoot1.right != null && pRoot2.left != null && pRoot1.right.val != pRoot2.left.val)
return false;
//右 左子树不为null,但val值不相等,不对称
return judge(pRoot1.left,pRoot2.right) && judge(pRoot1.right,pRoot2.left);
//最后进行递归判断
}
}
59 按之字形顺序打印二叉树
请实现一个函数按照之字形打印二叉树,即第一行按照从左到右的顺序打印,第二层按照从右至左的顺序打印,第三行按照从左到右的顺序打印,其他行以此类推。
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 ArrayList<ArrayList<Integer>> Print(TreeNode pRoot) {
ArrayList<ArrayList<Integer>> ret = new ArrayList<>();
if (pRoot == null) {
return ret;
}
ArrayList<Integer> list = new ArrayList<>();
LinkedList<TreeNode> queue = new LinkedList<>();
queue.addLast(null);
//层分隔符
queue.addLast(pRoot);
boolean leftToRight = true;
while (queue.size() != 1) {
TreeNode node = queue.removeFirst();
if (node == null) {
//到达层分隔符
Iterator<TreeNode> iter = null;
if (leftToRight) {
iter = queue.iterator();
//从前往后遍历
} else {
iter = queue.descendingIterator();
//从后往前遍历
}
leftToRight = !leftToRight;
while (iter.hasNext()) {
TreeNode temp = (TreeNode)iter.next();
list.add(temp.val);
}
ret.add(new ArrayList<Integer>(list));
list.clear();
queue.addLast(null);
//添加层分隔符
continue;
//一定要continue
}
if (node.left != null) {
queue.addLast(node.left);
}
if (node.right != null) {
queue.addLast(node.right);
}
}
return ret;
}
}
60 把二叉树打印成多行
从上到下按层打印二叉树,同一层结点从左至右输出。每一层输出一行。
public class Solution {
ArrayList<ArrayList<Integer> > Print(TreeNode pRoot)
{
ArrayList<ArrayList<Integer>> list1 = new ArrayList<ArrayList<Integer>>();
LinkedList<TreeNode> queue = new LinkedList<TreeNode>();
if(pRoot == null)
{
return list1;
}
TreeNode current = pRoot;
queue.offer(current);
int count;//记录当前层已经打印的个数
int last;//记录当前层一个有多少个
while(!queue.isEmpty())
{
count = 0;
last = queue.size();
ArrayList<Integer> list2 = new ArrayList<Integer>();
//打印一层
while(count < last)
{
current = queue.pop();//出队一个节点并将气质加入到list2中
list2.add(current.val);
count++;//每出队一个几点就增加一个当前层已经打印的节点个数
if(current.left != null)
queue.offer(current.left);
if(current.right != null)
queue.offer(current.right);
}
list1.add(list2);
}
return list1;
}
}
61 序列化二叉树
请实现两个函数,分别用来序列化和反序列化二叉树
/*
public class TreeNode {
int val = 0;
TreeNode left = null;
TreeNode right = null;
public TreeNode(int val) {
this.val = val;
}
}
*/
public class Solution {
//使用前序遍历序列化二叉树
String Serialize(TreeNode root) {
StringBuffer sb=new StringBuffer();
if(root==null){
//空节点(#)
sb.append("#,");
return sb.toString();
}
sb.append(root.val+",");
sb.append(Serialize(root.left));
sb.append(Serialize(root.right));
return sb.toString();
}
//反序列化:根据某种遍历方式得到的序列化字符串结果,重构二叉树
int index=-1;
TreeNode Deserialize(String str) {
index++;
int len=str.length();
if(index>=len) return null;
//以逗号分隔,返回一个字符串数组
String[] str1=str.split(",");
TreeNode node=null;
//遍历str1数组,重构二叉树:当前遍历元素非 # 则作为一个结点插入树中,作为上一个结点的左儿子;
//当前遍历元素为 # 则表示此子树已结束,遍历下一个元素作为上一个结点的右孩子
//即遍历到数字作为上一个结点的左孩子,遇到#变向作为上一个结点的右孩子
if(!str1[index].equals("#")){
node=new TreeNode(Integer.valueOf(str1[index]));
node.left=Deserialize(str);
node.right=Deserialize(str);
}
return node;
}
}
62 二叉搜索树的第k个结点
给定一棵二叉搜索树,请找出其中的第k小的结点。例如, (5,3,7,2,4,6,8) 中,按结点数值大小顺序第三小结点的值为4。
public class Solution{
int index = 0;
TreeNode KthNode(TreeNode ppRootOfTree, int k){
if (ppRootOfTree != null){
TreeNode treeNode = KthNode(ppRootOfTree.left,k);
if (treeNode != null ) return treeNode;
index ++;
if (index == k) return ppRootOfTree;
treeNode = KthNode(ppRootOfTree.right,k);
if (treeNode != null) return treeNode;
}
return null;
}
}
63 数据流的中位数
如何得到一个数据流中的中位数?如果从数据流中读出奇数个数值,那么中位数就是所有数值排序之后位于中间的数值。如果从数据流中读出偶数个数值,那么中位数就是所有数值排序之后中间两个数的平均值。我们使用Insert()方法读取数据流,使用GetMedian()方法获取当前读取数据的中位数。
import java.util.Comparator;
import java.util.PriorityQueue;
public class Solution {
private int count = 0;
private PriorityQueue<Integer> minHeap = new PriorityQueue<>();
private PriorityQueue<Integer> maxHeap = new PriorityQueue<Integer>(15,new Comparator<Integer>(){
@Override
public int compare(Integer o1,Integer o2){
return o2-o1;
}
});
public void Insert(Integer num) {
if(count%2==0){
maxHeap.offer(num);
int filteredMaxNum = maxHeap.poll();
minHeap.offer(filteredMaxNum);
}else{
minHeap.offer(num);
int filteredMinNum = minHeap.poll();
maxHeap.offer(filteredMinNum);
}
count++;
}
public Double GetMedian() {
if(count%2==0){
return new Double((minHeap.peek()+maxHeap.peek()))/2;
}else{
return new Double(minHeap.peek());
}
}
}
64 滑动窗口的最大值
给定一个数组和滑动窗口的大小,找出所有滑动窗口里数值的最大值。例如,如果输入数组{2,3,4,2,6,2,5,1}及滑动窗口的大小3,那么一共存在6个滑动窗口,他们的最大值分别为{4,4,6,6,6,5}; 针对数组{2,3,4,2,6,2,5,1}的滑动窗口有以下6个: {[2,3,4],2,6,2,5,1}, {2,[3,4,2],6,2,5,1}, {2,3,[4,2,6],2,5,1}, {2,3,4,[2,6,2],5,1}, {2,3,4,2,[6,2,5],1}, {2,3,4,2,6,[2,5,1]}。
https://blog.youkuaiyun.com/gg543012991/article/details/52854245
import java.util.*;
public class Solution {
public ArrayList<Integer> maxInWindows(int[] num,int size){
ArrayList<Integer> ret = new ArrayList<>();
if(num == null){
return ret;
}
if(num.length < size || size < 1){
return ret;
}
LinkedList<Integer> indexDeque = new LinkedList<>(); //用于保存滑动窗口中的数字
/*
滑动窗口内部,用于判断窗口中的最大值
*/
for(int i = 0; i < size - 1; i++){
while(!indexDeque.isEmpty()&& num[i] > num[indexDeque.getLast()]){ //getLast为插入端
indexDeque.removeLast(); //将前面比K小的直接移除队列,因为不可能成为滑动窗口的最大值
}
indexDeque.addLast(i); //将数字存入滑动窗口中
}
/*
滑动整个窗口
*/
for(int i = size - 1; i < num.length; i++){
while(!indexDeque.isEmpty() && num[i] > num[indexDeque.getLast()]){ //getLast为插入端,队尾
indexDeque.removeLast(); //将前面比K小的直接移除队列,因为不可能成为滑动窗口的最大值
}
indexDeque.addLast(i);
//System.out.println("indexDeque = " + indexDeque.getFirst() + ",i = " + i); //getFirst为允许删除端,队头
if(i - indexDeque.getFirst() + 1 > size){
indexDeque.removeFirst();
}
ret.add(num[indexDeque.getFirst()]); //每次添加的是num[indexDeque.getFirst()],而不是indexDeque.getFirst().
}
return ret;
}
}
65 矩形中的路径
请设计一个函数,用来判断在一个矩阵中是否存在一条包含某字符串所有字符的路径。路径可以从矩阵中的任意一个格子开始,每一步可以在矩阵中向左,向右,向上,向下移动一个格子。如果一条路径经过了矩阵中的某一个格子,则之后不能再次进入这个格子。 例如 a b c e s f c s a d e e 这样的3 X 4 矩阵中包含一条字符串"bcced"的路径,但是矩阵中不包含"abcb"路径,因为字符串的第一个字符b占据了矩阵中的第一行第二个格子之后,路径不能再次进入该格子。
public class Solution {
public boolean hasPath(char[] matrix, int rows, int cols, char[] str)
{
if (matrix == null || str == null || matrix.length < 1|| matrix.length<str.length) return false;
boolean[] visited = new boolean[rows*cols];
int curLength = 0;
for (int i = 0;i < rows;++i) {
for (int j = 0; j < cols; ++j) {
if (coreHasPath(matrix,rows,cols,i,j,str,visited,curLength)) return true;
}
}
return false;
}
private boolean coreHasPath(char[] matrix, int rows, int cols, int row, int col, char[] str, boolean[] visited, int curLength) {
if (curLength == str.length) return true;
boolean hasPath = false;
if (row>=0 && row < rows && col>=0 && col<cols && !visited[row*cols+col] && matrix[row*cols+col] == str[curLength]) {
curLength++;
visited[row*cols+col] = true;
hasPath = coreHasPath(matrix,rows,cols,row-1,col,str,visited,curLength) ||
coreHasPath(matrix,rows,cols,row+1,col,str,visited,curLength) ||
coreHasPath(matrix,rows,cols,row,col-1,str,visited,curLength) ||
coreHasPath(matrix,rows,cols,row,col+1,str,visited,curLength);
if (!hasPath) {
visited[row*cols+col] = false; //return hasPath回到上一层调用,curLength的值会自动回到上一层调用时的值
}
}
return hasPath;
}
}
66 机器人的运动范围
地上有一个m行和n列的方格。一个机器人从坐标0,0的格子开始移动,每一次只能向左,右,上,下四个方向移动一格,但是不能进入行坐标和列坐标的数位之和大于k的格子。 例如,当k为18时,机器人能够进入方格(35,37),因为3+5+3+7 = 18。但是,它不能进入方格(35,38),因为3+5+3+8 = 19。请问该机器人能够达到多少个格子?
public class Solution {
public int movingCount(int threshold, int rows, int cols) {
if (rows <= 0 || cols <= 0 || threshold < 0)
return 0;
boolean[] isVisited = new boolean[rows * cols];
int count = movingCountCore(threshold, rows, cols, 0, 0, isVisited);// 用两种方法试一下
return count;
}
private int movingCountCore(int threshold, int rows, int cols, int row, int col, boolean[] isVisited) {
if (row < 0 || col < 0 || row >= rows || col >= cols || isVisited[row * cols + col]
|| cal(row) + cal(col) > threshold)
return 0;
isVisited[row * cols + col] = true;
return 1 + movingCountCore(threshold, rows, cols, row - 1, col, isVisited)
+ movingCountCore(threshold, rows, cols, row + 1, col, isVisited)
+ movingCountCore(threshold, rows, cols, row, col - 1, isVisited)
+ movingCountCore(threshold, rows, cols, row, col + 1, isVisited);
}
private int cal(int num) {
int sum = 0;
while (num > 0) {
sum += num % 10;
num /= 10;
}
return sum;
}
}