JZ31:从1到n,1出现的次数
题目描述:1~13中包含1的数字有1、10、11、12、13因此共出现6次,(从1 到 n 中1出现的次数?)。
解题思路:把这个数转化成字符数组,逐个去遍历统计
public class Solution {
public int NumberOf1Between1AndN_Solution(int n) {
int count=0;
while(n>0){
String str=String.valueOf(n);//转换成字符串
char[] arr=str.toCharArray();
for(int i=0;i<arr.length;i++){
if(arr[i]=='1'){
count++;
}
}
n--;
}
return count;
}
}
JZ32:把数组排成最小的数
题目描述:输入一个正整数数组,把数组里所有数字拼接起来排成一个数,打印能拼接出的所有数字中最小的一个。例如输入数组{3,32,321},则打印出这三个数字能排成的最小数字为321323。
解题思路:比较两个字符串s1, s2大小的时候,先将它们拼接起来,比较s1+s2,和s2+s1那个大,如果s1+s2大,那说明s2应该放前面,所以按这个规则,s2就应该排在s1前面。比如3和32拼接成332,32和3拼接成323,332大于323,所以3就和32交换位置,以此推论。
public class Solution{
public String PrintMinNumber(int[] numbers){
if(numbers==null||numbers.length==0){
return "";
}
for(int i=0;i<numbers.length;i++){
for(int j=i+1;j<numbers.length;j++){
int sum1=Integer.valueOf(numbers[i]+""+numbers[j]);
int sum2=Integer.valueOf(numbers[j]+""+numbers[i]);
if(sum1>sum2){
int temp=numbers[j];
numbers[j]=numbers[i];
numbers[i]=temp;
}
}
}
String str=new String("");
for(int i=0;i<numbers.length;i++){
str=str+numbers[i];
}
return str;
}
}
JZ33:丑数
题目描述:把只包含质因子2、3和5的数称作丑数(Ugly Number)。例如6、8都是丑数,但14不是,因为它包含质因子7。 习惯上我们把1当做是第一个丑数。求按从小到大的顺序的第N个丑数。
解题思路:首先从丑数的定义我们知道,一个丑数的因子只有2,3,5,那么丑数p = 2 ^ x * 3 ^ y * 5 ^ z,换句话说一个丑数一定由另一个丑数乘以2或者乘以3或者乘以5得到,我们只用比较3个数:用于乘2的最小的数、用于乘3的最小的数,用于乘5的最小的,
import java.util.ArrayList;
public class Solution {
public int GetUglyNumber_Solution(int index) {
if(index<=0){
return 0;
}
ArrayList<Integer> list=new ArrayList<>();
list.add(1);
int i2=0,i3=0,i5=0;
while(list.size()<index){
int m2=list.get(i2)*2;
int m3=list.get(i3)*3;
int m5=list.get(i5)*5;
int min=Math.min(m2,Math.min(m3,m5));
list.add(min);
if(min==m2)i2++;
if(min==m3)i3++;
if(min==m5)i5++;
}
return list.get(list.size()-1);
}
}
JZ34:第一个只出现一次的字符
题目描述:在一个字符串(0<=字符串长度<=10000,全部由字母组成)中找到第一个只出现一次的字符,并返回它的位置, 如果没有则返回 -1(需要区分大小写).(从0开始计数)
解题思路:借助java的indexof和lastIndexof方法,两个相等直接返回
public class Solution {
public int FirstNotRepeatingChar(String str) {
for (int i = 0; i < str.length(); i++) {
char ch = str.charAt(i);
//indexof:返回第一次出现的指定字符串在此字符串中的索引
//同理,返回最后一次出现的索引
if (str.indexOf(ch) == str.lastIndexOf(ch))
return i;
}
return -1;
}
}
JZ35:数组中的逆序对
题目描述:在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数P。并将P对1000000007取模的结果输出。 即输出P%1000000007
解题思路:这种情况下用归并排序是最合适的,归并排序的思想是先分在和。在分完的时候是统计逆序数对的最好时机。
public class Solution {
//统计逆序对的个数
int cnt;
public int InversePairs(int [] array) {
if(array.length != 0){
divide(array,0,array.length-1);
}
return cnt;
}
//归并排序的分治---分
public void divide(int[] arr,int start,int end){
if(start >= end)//递归出口
return;
int mid = start + (end - start)/2;
//递归分
divide(arr,start,mid);
divide(arr,mid+1,end);
merge(arr,start,mid,end);//治
}
public void merge(int[] arr,int start,int mid,int end){
int[] temp = new int[end-start+1];
int i=start,j=mid+1,k=0;
//下面就开始两两进行比较,若前面的数大于后面的数,就构成逆序对
while(i<=mid && j<=end){
//若前面小于后面,直接存进去,并且移动前面数所在的数组的指针即可
if(arr[i] <= arr[j]){
temp[k++] = arr[i++];
}else{
temp[k++] = arr[j++];
//a[i]>a[j]了,那么这一次,从a[i]开始到a[mid]必定都是大于这个a[j]的,因为此时分治的两边已经是各自有序了
cnt = (cnt+mid-i+1)%1000000007;
}
}
//各自还有剩余的没比完,直接赋值即可
while(i<=mid)
temp[k++] = arr[i++];
while(j<=end)
temp[k++] = arr[j++];
//覆盖原数组
for (k = 0; k < temp.length; k++)
arr[start + k] = temp[k];
}
}
JZ36:两个链表的第一个公共节点
题目描述:输入两个链表,找出它们的第一个公共结点。(注意因为传入数据是链表,所以错误测试数据的提示是用其他方式显示的,保证传入数据是正确的)
解题思路:让p1 p2都往后遍历,想等了说明找到了,返回,不相等但其中一个为空了就返回另一个
public class Solution {
public ListNode FindFirstCommonNode(ListNode pHead1, ListNode pHead2) {
ListNode p1=pHead1;
ListNode p2=pHead2;
while(p1!=p2){//两个不相等就往后遍历
p1 = (p1==null ? pHead2 : p1.next);//这个为空了就返回另一个
p2 = (p2==null ? pHead1 : p2.next);
}
return p1;
}
}
JZ37:数字在排序数组中出现的次数
解题思路:二分查找的前提就是有序,所以这道题就用二分查找来做,找到k值出现的左和右,然后统计
public class Solution {
public int GetNumberOfK(int [] array , int k) {
if(array==null||array.length==0){
return 0;
}
int left=0,right=array.length-1,mid=0;
while(left<right){//二分查找的过程
mid =left+(right-left)/2;
if(array[mid]>k){
right=mid-1;
}
else if(array[mid]<k){
left=mid+1;
}
else{
break;
}
}
int count=0;
for(int i=left;i<=right;i++){//找到k值出现的左和右,然后统计
if(array[i]==k)
count++;
}
return count;
}
}
JZ38:求二叉树的深度
解题思路:树的题目一般都用递归,把左边统计一下,再把右边统计一下,返回大的那个就是它的深度
public class Solution {
public int TreeDepth(TreeNode root) {
if(root==null){
return 0;
}
int left=TreeDepth(root.left);
int right=TreeDepth(root.right);
return Math.max(left,right)+1;
}
}
JZ39:平衡二叉树
题目描述:给一棵树,判断是不是平衡二叉树
解题思路:首先知道平衡二叉树任意节点的子树的高度差都小于等于1,判断树是否为空,空则返回true,判断左右子树深度差超过1,返回false.若通过2的判断,对左右子树也判断是否都是平衡二叉树,判断函数为函数自身,递归调用
public class Solution {
public int TreeDepth(TreeNode root) {
if(root==null){
return 0;
}
if(root.left==null && root.right==null){
return 1;
}
return 1+Math.max(TreeDepth(root.left),TreeDepth(root.right));
}
public boolean IsBalanced_Solution(TreeNode root) {
if(root==null) return true;
if(Math.abs(TreeDepth(root.left)-TreeDepth(root.right))>1)
return false;
return IsBalanced_Solution(root.left) && IsBalanced_Solution(root.right);
}
}
JZ40:数组中只出现一次的数字
题目描述:一个整型数组里除了两个数字之外,其他的数字都出现了两次。请写程序找出这两个只出现一次的数字。
解题思路:异或运算规则,相同为0不同为1,当只有一个数出现一次时,我们把数组中所有的数,依次异或运算,成对的就会被异或掉,最后剩下的就是要的单数。还有一种简单方法就是用HashMap的性质,
方法一:运用异或性质
public class Solution {
public void FindNumsAppearOnce(int [] array,int num1[] , int num2[]) {
int num=0;
for(int i=0;i<array.length;i++){
num^=array[i];//所有数异或,结果为不同的两个数字的异或
}
int count=0;//标志位,记录num中的第一个1出现的位置
for(;count<array.length;count++){
if((num&(1<<count))!=0){
break;
}
}
num1[0]=0;
num2[0]=0;
for(int i=0;i<array.length;i++){
if((array[i]&(1<<count))==0){//标志位为0的为一组,异或后必得到一个数字(这里注意==的优先级高于&,需在前面加())
num1[0]^=array[i];
}else{
num2[0]^=array[i];//标志位为1的为一组
}
}
}
}
方法二:运用HashaMap
import java.util.HashMap;
public class Solution {
public void FindNumsAppearOnce(int [] array,int num1[] , int num2[]) {
HashMap<Integer,Integer> map=new HashMap<>();
for(int i=0;i<array.length;i++){
if(map.containsKey(array[i])){
map.put(array[i],2);
}else{
map.put(array[i],1);//把单独的这个数就统计出来了
}
}
int count=0;
for(int i=0;i<array.length;i++){
if(map.get(array[i])==1){
if(count==0){
num1[0]=array[i];
count++;
}
else{
num2[0]=array[i];
}
}
}
}
}