【剑指offer@JZ41--JZ50】

JZ41:和为S的连续正数序列

题目描述:小明很喜欢数学,有一天他在做数学作业时,要求计算出9~16的和,他马上就写出了正确答案是100。但是他并不满足于此,他在想究竟有多少种连续的正数序列的和为100(至少包括两个数)。没多久,他就得到另一组连续正数和为100的序列:18,19,20,21,22。现在把问题交给你,你能不能也很快的找出所有和为S的连续正数序列?
解题思路:因为要连续,所以求的的这个序列公差为1(根据等差数列的求和公式:S = (1 + n) * n / 2),并且中间值就是这段数列平均值的大小,向上面20就是这段数列的平均值,假设序列长度为n,中间值就是S/N,知道序列长度和中间值,这个序列也就出来了,但有个问题,数列长度为奇数时,中间那个数正好是平均数,为偶数时,中间两个数相加除以2,才是平均数,到底n最大长度是多少,根据求和公式,就可以把最大的n算出来,遍历的时候也只需要遍历最大的n,

import java.util.ArrayList;
public class Solution{
    public ArrayList<ArrayList<Integer> > FindContinuousSequence(int sum) {
       ArrayList<ArrayList<Integer>> list=new ArrayList<>();
        //这个n就是根据求和公式所得到得最大序列长,最小由题意知是2
        for(int n=(int)Math.sqrt(2*sum);n>=2;n--){
            //n&1等于1说明n不为0,sum%n==0说明序列为奇数,后面说明序列长为偶数,
            //后面是偶数的情况,余数是除数的一半,比如5、6、7、8、合为26,余数为2商为4.
            if ((n&1) ==1&&sum%n==0||(sum%n)*2 == n){
                ArrayList<Integer> answer=new ArrayList<>();
                //决定这个序列的起始值是几,sum/n是中间那个值,往前推(n-1)/2就是起始值,
                 for (int j = 0,k =(sum/n)-(n-1)/2;j<n;j++,k++){
                     answer.add(k);
                 } 
                list.add(answer);
            }
        }
        return list;
    }
}

JZ42:和为s的两个数组

题目描述:输入一个递增排序的数组和一个数字S,在数组中查找两个数,使得他们的和正好是S,如果有多对数字的和等于S,输出两个数的乘积最小的。
解题思路:左右夹击,来例子看,比如一个数组2、4、6、7、8、10、12给一个数为14,满足条件的有2和12乘积为24,4和10乘积为40,6和8乘积为48,不难发现,最外层的积就是最小的,定义两个指针,一个从最左边一个从最右边,不断向两边逼近,大了右边往左移,小了左边往右移。

import java.util.ArrayList;
public class Solution {
    public ArrayList<Integer> FindNumbersWithSum(int [] array,int sum) {
        ArrayList<Integer> list=new ArrayList<>();
        if(array==null||array.length<2){//数组为空直接返回
            return list;
        }
        int left=0,right=array.length-1;
        while(left<right){//循环条件
            if(array[left]+array[right]==sum){
                list.add(array[left]);
                list.add(array[right]);
                return list;
            }
            else if(array[left]+array[right]>sum){
                right--;
            }
            else{
                left++;
            }
        }
        return list;
    }
}

JZ43:左旋字符串

题目描述:字符序列S=”abcXYZdef”,要求输出循环左移3位后的结果,即“XYZdefabc”
解题思路:跟字符串有关的题应该想到用字符串的常见方法去解决,这道题的思路就是先把n到str.length剪切出来,再用append方法把前面切出去的加到后面。

public class Solution {
    public String LeftRotateString(String str,int n) {
        if(str == null||n<0){
            return null;
        }
        String string = new String();
        if(n <= str.length()) {
            //substring包括前不包括后
            StringBuffer sb = new StringBuffer(str.substring(n, str.length()));
            String s1 = str.substring(0, n);
            string = sb.append(s1).toString();
             
        }
        return string;
    }
}

JZ44:翻转单词顺序列

题目描述:“student. a am I”。后来才意识到,这家伙原来把句子单词的顺序翻转了,正确的句子应该是“I am a student.”
解题思路:用StringBuilder的append方法逐个逆序添加,需要注意的是i=0时不需要再添加空格了,所以单独处理一下

public class Solution{
    public String ReverseSentence(String str) {
        if (str.trim().length()==0) {//字符串为0返回字符串
            return str;
        }
        String[] arr=str.split(" ");
        StringBuilder sb=new StringBuilder();
        for (int i = arr.length-1; i >0; i--) {
            sb.append(arr[i]+" ");//z逐个添加
        }
        sb.append(arr[0]);
        return sb.toString();
    }
}

JZ45:扑克牌顺子·

题目描述: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。
解题思路:首先把大小王的张数统计出来,用一个set去存放都有那些牌,因为set不允许重复。然后用大小王的张数加上set的size要是不等于5,说明有对子,等于5时,还要判断最大值和最小值得差在不在5之内,

import java.util.*;
public class Solution{
    public boolean isContinuous(int [] numbers) {
        if(numbers.length<5||numbers.length>5){//数组的长度不符合就直接返回错
            return false;
        }
        Arrays.sort(numbers);
        int count=0;
        TreeSet<Integer> set=new TreeSet<>();
        for(int i=0;i<numbers.length;i++){
            if(numbers[i]==0){//把大小王的张数统计出来
                count++;
            }else{
                set.add(numbers[i]);//利用了set不允许重复的性质,防止有对子出现
            }
        }
        if((count+set.size())!=5){//和不为5说明有对子
            return false;
        }
        if((set.last()-set.first())<5){
            //因为是顺子,是个公差为1的数列,最大值减最小值肯定在5之内
            return true;
        }
        return false;
    }
}

JZ46:孩子们的游戏

题目描述:游戏是这样的:首先,让小朋友们围成一个大圈。然后,他随机指定一个数m,让编号为0的小朋友开始报数。每次喊到m-1的那个小朋友要出列唱首歌,然后可以在礼品箱中任意的挑选礼物,并且不再回到圈中,从他的下一个小朋友开始,继续0…m-1报数…这样下去…直到剩下最后一个小朋友,可以不用表演,请你试着想下,哪个小朋友会得到这份礼品呢?(注:小朋友的编号是从0到n-1),如果没有小朋友,请返回-1
解题思路:直接用约瑟夫环公式求解

public class Solution
{
    public int LastRemaining_Solution(int n, int m)
    {
        if(n==0||m==0){
            return -1;
        }
        int s=0;
        for(int i=2;i<=n;i++)
        {
            s=(s+m)%i;//约瑟夫环公式
        }   
       return s ;
    }
}

JZ47:求1+2+3…n,

解题思路:直接等差数列求和公式搞定(Sn=n*(a1+an)/2)

public class Solution {
    public int Sum_Solution(int n) {
        int sum=n*(1+n)>>1;//右移相当于除以2
        return sum;
    }
}

JZ48:不用加减乘除做加法

解题思路:两个数异或相当于每一位相加,而不考虑进位;两个数相与,并左移一位:相当于求得进位;将上述两步的结果相加

public class Solution{
public int Add(int num1,int num2) {
    while( num2!=0 ){
        int sum = num1 ^ num2;
        int carray = (num1 & num2) << 1;
        num1 = sum;
        num2 = carray;
    }
    return num1;
    }
}

JZ49:把字符串转换成整数

题目描述:将一个字符串转换成一个整数,要求不能使用字符串转换整数的库函数。 数值为0或者字符串不是一个合法的数值则返回0
解题思路:先处理一下正负号,然后从前往后遍历,每次×10逐个相加。

public class Solution{
    public static int StrToInt(String str) {
        if(str==null||str.length()==0) {//如果输入的字符串为空。直接返回0
            return 0;
        }
        boolean tag=false;
        int sum=0;
        char[] arr=str.toCharArray();
        if(arr[0]=='-') {//如果第一个字符为负号,则标志位要进行变号。
            tag = true;
        }
        for(int i=0;i<arr.length;i++){
            if(i==0&&(arr[i]=='+'||arr[i]=='-')) {//第一个元素为正或者负才能继续往下判断
                continue;
            }
            if(arr[i]<'0'||arr[i]>'9') {//如果这个字符不在0到9范围内说明输入不合法
                return 0;
            }
            sum=sum*10+(arr[i]-'0');//到这儿就可以计算这个int数了
        }
        return tag?(0-sum):sum;//用三目运算符来return结果,为假说明
        //是整数,直接返回sum,否则返回负的sum
    }
}

JZ50:数组中重复的数字

题目描述:在一个长度为n的数组里的所有数字都在0到n-1的范围内。 数组中某些数字是重复的,但不知道有几个数字是重复的。也不知道每个数字重复几次。请找出数组中任意一个重复的数字。 例如,如果输入长度为7的数组{2,3,1,0,2,5,3},那么对应的输出是第一个重复的数字2
解题思路:运用TreeSet不允许重复的性质,每添加一个就去看一下set的size涨了没,要是没涨就说明找到重复的这个值了

import java.util.TreeSet;
public class Solution {
    // 这里要特别注意~返回任意重复的一个,赋值duplication[0]
    public boolean duplicate(int numbers[],int length,int [] duplication) {
        if(length==0){
            return false;
        }
        TreeSet<Integer> set=new TreeSet();
        for(int i=0;i<numbers.length;i++){
            set.add(numbers[i]);
            if(set.size()!=i+1){
                duplication[0]=numbers[i];
                return true;
            }
        }
        return false;
    }
}

猜你喜欢

转载自blog.csdn.net/chris__x/article/details/106963446