剑指offer 第十天
37.数字在排序数组中出现的次数
统计一个数字在排序数组中出现的次数。
采用二分查找法
/* 方法一:时间复杂度O(n),不可选 */ public class Solution { public int GetNumberOfK(int [] array , int k) { if(array.length == 0) return 0; int count = 0; for(int i = 0 ; i < array.length ; i++){ if(array[i] == k){ count++; }else{ if(count != 0) break; } } return count; } } /* 方法二:首选!先采用二分查找法,在数组中查找到第一个K和第二个K,总时间复杂度O(logn) */ public class Solution { public int GetNumberOfK(int[] array,int k){ if(array.length == 0) return 0; int first = getFirstK(array,k,0,array.length-1); int last = getLastK(array,k,0,array.length-1); if(first > -1 && last > -1) return last - first + 1; return 0; } public int getFirstK(int[] array,int k,int start,int end){ if(start > end) return -1; int midIdx = (end + start)/2; if(array[midIdx] == k){ if((midIdx > 0 && array[midIdx-1] != k) || midIdx == 0) return midIdx; else{ end = midIdx - 1; return getFirstK(array,k,start,end); } }else if(array[midIdx] > k){ end = midIdx - 1; }else if(array[midIdx] < k){ start = midIdx +1; } return getFirstK(array,k,start,end); } public int getLastK(int[] array,int k ,int start,int end){ if(start > end) return -1; int midIdx = (start + end)/2; if(array[midIdx] == k){ if((midIdx < array.length-1 && array[midIdx+1] != k) || midIdx == array.length-1) return midIdx; else start = midIdx + 1; }else if(array[midIdx] > k){ end = midIdx - 1; }else if(array[midIdx] < k){ start = midIdx + 1; } return getLastK(array,k,start,end); } }
38.二叉树的深度
输入一棵二叉树,求该树的深度。从根结点到叶结点依次经过的结点(含根、叶结点)形成树的一条路径,最长路径的长度为树的深度。
/** 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; int left = TreeDepth(root.left); int right = TreeDepth(root.right); if(left>right) return left+1; else return right+1; } }
39.平衡二叉树
输入一棵二叉树,判断该二叉树是否是平衡二叉树。如果某二叉树中任意节点的左、右子树的深度相差不超过1,那么他就是一棵平衡二叉树。
解法一:不够简便
public class Solution { public boolean IsBalanced_Solution(TreeNode root) { if(root == null) return true; int left = TreeDepth(root.left); int right = TreeDepth(root.right); if((left-right)>1||(left-right)<-1) return false; else return IsBalanced_Solution(root.left) && IsBalanced_Solution(root.right); } public int TreeDepth(TreeNode root){ if(root == null) return 0; int left = TreeDepth(root.left); int right = TreeDepth(root.right); return left > right ? left+1 : right+1; } }
解法二:推荐!后序遍历二叉树,只需遍历一遍即可。
public class Solution { public boolean IsBalanced_Solution(TreeNode root) { return getDepth(root) != -1; } public int getDepth(TreeNode root){ if(root == null) return 0; int left = getDepth(root.left); if(left == -1) return -1; int right = getDepth(root.right); if(right == -1) return -1; return Math.abs(left-right) > 1 ? -1 : Math.max(left,right) + 1; } }
40.数组中只出现一次的数字
一个整型数组里除了两个数字之外,其他的数字都出现了两次。请写程序找出这两个只出现一次的数字。
第一种:利用Set,空间复杂度为O(N)
//num1,num2分别为长度为1的数组。传出参数 //将num1[0],num2[0]设置为返回结果 import java.util.HashSet; import java.util.Iterator; public class Solution { public void FindNumsAppearOnce(int [] array,int num1[] , int num2[]) { HashSet<Integer> set = new HashSet<Integer>(); for(int i = 0;i<array.length;i++){ if(set.contains(array[i])){ set.remove(array[i]); }else{ set.add(array[i]); } } boolean isFirst = true; Iterator iter = set.iterator(); while(iter.hasNext()){ if(isFirst){ num1[0] = (int)iter.next(); isFirst = false; }else num2[0] = (int)iter.next(); } } }
41.数组中只出现一次的数字
一个整型数组里除了两个数字之外,其他的数字都出现了两次。请写程序找出这两个只出现一次的数字。
按位运算:异或、位移
//num1,num2分别为长度为1的数组。传出参数 //将num1[0],num2[0]设置为返回结果 public class Solution { public void FindNumsAppearOnce(int [] array,int num1[] , int num2[]) { int OR = 0; for(int i = 0;i<array.length;i++) OR ^= array[i]; int idx = 0;//OR从后数第几位是1,从1开始 while(OR != 0){ OR = OR >> 1; idx++; } num1[0] = 0; num2[0] = 0; for(int i = 0;i<array.length;i++){ if((array[i]&(1<<(idx-1))) == 0) num1[0] ^= array[i]; else num2[0] ^= array[i]; } } }
42.和为S的连续正数序列
小明很喜欢数学,有一天他在做数学作业时,要求计算出9~16的和,他马上就写出了正确答案是100。但是他并不满足于此,他在想究竟有多少种连续的正数序列的和为100(至少包括两个数)。没多久,他就得到另一组连续正数和为100的序列:18,19,20,21,22。现在把问题交给你,你能不能也很快的找出所有和为S的连续正数序列? Good Luck!
输出描述:
输出所有和为S的连续正数序列。序列内按照从小至大的顺序,序列间按照开始数字从小到大的顺序
import java.util.ArrayList; public class Solution { public ArrayList<ArrayList<Integer> > FindContinuousSequence(int sum) { ArrayList<ArrayList<Integer>> result = new ArrayList<ArrayList<Integer>>(); int small = 1,big = 2,listSum = 3; int mid = (sum+1)/2; while(small < mid && small < big){ if(listSum == sum){ //注意此处很容易出现死循环,当检测出一个序列后,记得变化small数值 ArrayList<Integer> listResult = new ArrayList<>(); for(int i = small;i <= big;i++) listResult.add(i); result.add(listResult); listSum -= small; small++; }else if(listSum < sum){ big++; listSum += big; }else if(listSum > sum){ listSum -= small; small++; } } return result; } }
43.和为S的两个数
输入一个递增排序的数组和一个数字S,在数组中查找两个数,是的他们的和正好是S,如果有多对数字的和等于S,输出两个数的乘积最小的。
解析:
其实找的就是数组最两侧满足和为S的数字,因为:
z=xy
x+y=s
z=x(s-x)=sx-x^2 函数图像为向下开口的抛物线,两段数值小中间大。所以取两边的值。
import java.util.ArrayList; public class Solution { public ArrayList<Integer> FindNumbersWithSum(int [] array,int sum) { ArrayList<Integer> result = new ArrayList<>(); int p1 = 0,p2 = array.length-1; while(p1<p2){ if(array[p1]+array[p2] == sum){ result.add(array[p1]); result.add(array[p2]); return result; }else if(array[p1]+array[p2]>sum) p2--; else p1++; } return result; } }
44.坐旋转字符串
汇编语言中有一种移位指令叫做循环左移(ROL),现在有个简单的任务,就是用字符串模拟这个指令的运算结果。对于一个给定的字符序列S,请你把其循环左移K位后的序列输出。例如,字符序列S=”abcXYZdef”,要求输出循环左移3位后的结果,即“XYZdefabc”。是不是很简单?OK,搞定它!
==该题有好多种做法==
方法一:虽然AC,但是不是最优解
public class Solution { public String LeftRotateString(String str,int n) { if(n<0 || str==null || str.length() == 0) return ""; n %= str.length(); StringBuilder sb = new StringBuilder(); for(int i = n;i<str.length();i++){ sb.append(str.charAt(i)); } for(int i = 0;i<n;i++){ sb.append(str.charAt(i)); } return sb.toString(); } }
方法二
public class Solution { public String LeftRotateString(String str,int n) { if(n<0 || str==null || str.length() == 0) return ""; n %= str.length(); StringBuilder sb = new StringBuilder(); for(int i = n;i<str.length();i++){ sb.append(str.charAt(i)); } for(int i = 0;i<n;i++){ sb.append(str.charAt(i)); } return sb.toString(); } }
45.翻转字符串
牛客最近来了一个新员工Fish,每天早晨总是会拿着一本英文杂志,写些句子在本子上。同事Cat对Fish写的内容颇感兴趣,有一天他向Fish借来翻看,但却读不懂它的意思。例如,“student. a am I”。后来才意识到,这家伙原来把句子单词的顺序翻转了,正确的句子应该是“I am a student.”。Cat对一一的翻转这些单词顺序可不在行,你能帮助他么?
public class Solution { public String ReverseSentence(String str) { if(str.length()==0) return ""; char[] charArray = str.toCharArray(); Reverse(charArray,0,str.length()-1); int start = 0,end = 0; for(int i = 0;i < charArray.length;i++){ if(charArray[i] == ' '){ end = i-1; Reverse(charArray,start,end); start = i+1; } } Reverse(charArray,start,charArray.length-1); return String.valueOf(charArray); } public char[] Reverse(char[] charArray,int start,int end){ while(start<end){ char temp = charArray[start]; charArray[start] = charArray[end]; charArray[end] = temp; start++; end--; } return charArray; } }
- 《剑指offer》-用两个栈实现队列
- 剑指offer:数组中出现次数超过一半的数字
- 《剑指offer》在mac上编译通过的代码
- 剑指offer:(6)查找和排序:旋转数组中的最小值
- 剑指offer:求二叉树的深度
- 剑指offer 链表中环的入口结点
- 剑指offer-12.数值的整数次方
- JAV实现跳台阶问题(《剑指offer》)
- 剑指offer-二叉树的镜像
- java从入门到弃坑第十天
- 剑指offer--DP类题目汇总
- 剑指Offer——(16)合并两个排序的链表
- 剑指offer——二维数组中的查找
- 剑指Offer(第二版)面试题11:旋转数组的最小数字
- 剑指offer----字符流中第一个不重复的字符
- 剑指Offer-7
- 剑指offer 面试题20 顺时针打印矩阵
- 剑指offer-替换空格
- 剑指offer——替换空格
- 剑指offer面试题6-从尾到头打印链表-java