美文网首页
剑指Offer(java答案)(41-50)

剑指Offer(java答案)(41-50)

作者: 壮少Bryant | 来源:发表于2019-05-25 11:53 被阅读0次

    41、和为S的两个数字

    题目描述
    输入一个递增排序的数组和一个数字S,在数组中查找两个数,使得他们的和正好是S,如果有多对数字的和等于S,任意输出一对。
    输入数组{1,2,4,7,11,15}和15,输出4,11

    import java.util.ArrayList;
    public class Solution {
        /*
        * i,j分别表示数组两端下表
        * 当array[i]+array[j]>S时,j-- 尾端向前移动,两数据和增大
        * 当array[i]+array[j]=S时,将array[i],array[j]依次添加到ArrayList中
        * 当array[i]+array[j]<S时,i++前段向后移动,两数据和减小
        */
        public ArrayList<Integer> FindNumbersWithSum(int [] array,int sum) {
            ArrayList<Integer> list = new ArrayList<Integer>();
            if (array == null || array.length < 2) {
                return list;
            }
            int i=0,j=array.length-1;
            while(i<j){
                if(array[i]+array[j]==sum){
                list.add(array[i]);
                list.add(array[j]);
                    return list;
               }else if(array[i]+array[j]>sum){
                    j--;
                }else{
                    i++;
                }
                 
            }
            return list;
        }
    }
    

    扩展题:和为S的连续正数序列

    描述:输出所有和为S的连续正数序列。序列内按照从小至大的顺序,序列间按照开始数字从小到大的顺序

    import java.util.ArrayList;
    
    public class Solution {
        public static ArrayList<ArrayList<Integer>> FindContinuousSequence(int sum) {
            ArrayList<ArrayList<Integer>> list = new ArrayList<ArrayList<Integer>>();
            if (sum < 3)
                return list;
            ArrayList<Integer> l = new ArrayList<Integer>();
            int small = 2;
            int middle = (1 + sum) / 2;//因为至少连续2个且顺序增加,所以取中间值
            l.add(1);
            l.add(2);
            int s = 3;
            if (s == sum) {
                list.add(new ArrayList<Integer>(l));
            }
    
            while (small <= middle) {
                small++;
                s += small;
                l.add(small);
                if (s == sum) {
                    list.add(new ArrayList<Integer>(l));
                }
          //两个指针,若大,减去左边数字,若小,加右边数字
                while (s > sum && small <= middle) {
                    s -= l.remove(0);
                    if (s == sum) {
                        list.add(new ArrayList<Integer>(l));
                    }
                }
    
            }
            return list;
        }
    }
    

    42、反转单词

    描述:反转英文单词,例如,“student. a am I”反转成“I am a student.”

    思想:就是先翻转所有字符,再逐个单词翻转

    public class Solution {
         public String ReverseSentence(String str) {
             if(str==null||str.trim().equals(""))// trim掉多余空格
                 return str;
             String[] words = str.split(" ");// 以空格切分出各个单词
             StringBuffer buffer = new StringBuffer();
             for(int i=0;i<words.length;i++){
    
                 buffer.append(reverse1(words[i].toCharArray(), 0, words[i].length()-1)).append(" ");
             }
             if(buffer.length()>0)
                 buffer.deleteCharAt(buffer.length()-1);// 删除最后一个空格
             return reverse1(buffer.toString().toCharArray(), 0, buffer.length()-1);
          
     }
        private String reverse1(char[] str, int l, int r) {
             // TODO Auto-generated method stub
             if(l>r)
                 return "";
             char tmp;
             while(l<r){
                 tmp = str[l];
                 str[l] = str[r];
                 str[r] = tmp;
                 l++;
                 r--;
             }
             return String.valueOf(str);
         }
    }
    

    扩展题:字符串左移n位,abcde,左移2位,cdeab

    思路:前n位反转,后几位反转,最后总的反转

    public class Solution {
        public String LeftRotateString(String str,int n) {
            char[] chars = str.toCharArray();        
            if(chars.length < n) return "";
            reverse(chars, 0, n-1);
            reverse(chars, n, chars.length-1);
            reverse(chars, 0, chars.length-1);
            StringBuilder sb = new StringBuilder(chars.length);
            for(char c:chars){
                sb.append(c);
            }
            return sb.toString();
        }
         
        public void reverse(char[] chars,int low,int high){
            char temp;
            while(low<high){
                temp = chars[low];
                chars[low] = chars[high];
                chars[high] = temp;
                low++;
                high--;
            }
        }
    }
    

    44、扑克牌的顺序

    从扑克牌中抽取5张牌,判断是否连续,大小王是任意数字

    思路:选取5张牌,首先去0,然后进行排序,最大值减最小值是否小于等于4,大于4,为false,
    然后相邻相减应该大于0小于5,否的为false

    import java.util.ArrayList;
    import java.util.Collections;
    public class Solution {
        public boolean isContinuous(int [] numbers) {
            if(numbers == null || numbers.length == 0 || numbers.length > 5){
                return false;
            }
            ArrayList<Integer> al = new ArrayList<>();
            int len = numbers.length;
            int count = 0;
            for(int i = 0; i < len; i++){
            //必须去0,因为0可以是任意数字,如0,2,3,5,6,也是连续的
                if(0 == numbers[i]){
                    count++;
                }else{
                    al.add(numbers[i]);
                }      
            }
             //非0的排序
            Collections.sort(al);
            int len1 = al.size();
            //大于4,肯定false
            if(Math.abs(al.get(0) - al.get(len1 - 1)) > 4){
                return false;
            }
            for(int i = 0; i < len1 - 1; i++){
             //相邻的只差,大于0不能重复,大于4肯定false
                int temp = al.get(i + 1) - al.get(i);
                if(0 < temp && temp < 5){
                    continue;
                }else{
                    return false;
                }
            }
            return true;
        }
    }
    
    

    45、约瑟夫环问题:圆圈中最后一个数字

    题目描述:一个环,每次删除第m个数字,求最后一个数字,如0,1,2,3,4这5个数字,从0开始每次删除第3个数字,则依次删除2,0,4,1,最后一个数字是3

    第一种解法:数组O(m*N)

    public class Solution {
        public int LastRemaining_Solution(int n, int m) {
            if(n<1||m<1) return -1;
            int[] array = new int[n];
            int i = -1,step = 0, count = n;
            while(count>0){   //跳出循环时将最后一个元素也设置为了-1
                i++;          //指向上一个被删除对象的下一个元素。
                if(i>=n) i=0;  //模拟环。
                if(array[i] == -1) continue; //跳过被删除的对象。
                step++;                     //记录已走过的。
                if(step==m) {               //找到待删除的对象。
                    array[i]=-1;
                    step = 0;
                    count--;
                }        
            }
            return i;//返回跳出循环时的i,即最后一个被设置为-1的元素
        }
    }
    

    第二种:链表,O(N)

    import java.util.*;
    public class Solution {
        public int LastRemaining_Solution(int n, int m) {
            if (m == 0 || n == 0) {
                return -1;
            }
            ArrayList<Integer> data = new ArrayList<Integer>();
            for (int i = 0; i < n; i++) {
                data.add(i);
            }
            int index = -1;
            while (data.size() > 1) {
            //重点是此步
                index = (index + m) % data.size();
                data.remove(index);
                index--;
            }
            return data.get(0);
        }
    
    }
    

    第三种better解法:约瑟夫经典解法,O(N),空间复杂度O(1)

    public class Solution {
        public int LastRemaining_Solution(int n,int m) {
            if(n==0) return -1;
             
           int s=0;
           for(int i=2;i<=n;i++){
               s=(s+m)%i;
           }
           return s;
        }
    }
    

    46、求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 result = 0;
            int a = 1;
            boolean value = ((n!=0) && a == (result = Sum_Solution(n-1)));
            result += n;    
            return result;
        }
     
    }
    

    47、不用加减乘除做加法

    题目描述
    写一个函数,求两个整数之和,要求在函数体内不得使用+、-、*、/四则运算符号。

    思路:首先看十进制是如何做的: 5+7=12,三步走

    第一步:相加各位的值,不算进位,得到2。

    第二步:计算进位值,得到10. 如果这一步的进位值为0,那么第一步得到的值就是最终结果。

    第三步:重复上述两步,只是相加的值变成上述两步的得到的结果2和10,得到12。

    同样我们可以用三步走的方式计算二进制值相加: 5-101,7-111 第一步:相加各位的值,不算进位,得到010,二进制每位相加就相当于各位做异或操作,101^111。

    第二步:计算进位值,得到1010,相当于各位做与操作得到101,再向左移一位得到1010,(101&111)<<1。

    第三步重复上述两步, 各位相加 010^1010=1000,进位值为100=(010&1010)<<1。
    继续重复上述两步:1000^100 = 1100,进位值为0,跳出循环,1100为最终结果。

    public class Solution {
        public int Add(int num1,int num2) {
            while (num2!=0) {
                int temp = num1^num2;//不算进位,各位相加
                num2 = (num1&num2)<<1;//得到进位数
                num1 = temp;//与进位数相加,即循环以上操作
            }
            return num1;
        }
    }
    

    49、把字符串转换成整数

    此题主要是注意细节:
    1、功能测试:输入有+-号情况,区分正负数和0
    2、特殊输入:空字符串情况,输入非数字字符串情况,如a12
    3、边界值:最大正整数和最小负整数溢出情况

    public class Solution {
        public int StrToInt(String str)
        {
            if (str.equals("") || str.length() == 0)//空字符串情况
                return 0;
            char[] a = str.toCharArray();
            int i = 0;
            boolean fuhao = true;//+-符号位
            if (a[0] == '-'){
                fuhao = false;
                i = 1;//第一位如果是-号,则从第二位开始循环
            }           
            int sum = 0;
            for (; i < a.length; i++)
            {
                if (a[i] == '+')
                    continue;
                if (a[i] < 48 || a[i] > 57)
                    return 0;//有非数字字符
                sum = sum * 10 + a[i] - 48;
                
                //判断是否溢出,正整数最大0X7FFF FFFF,最小负整数0X8000 0000
                if((fuhao && sum > 0X7fffffff) || (!fuhao && sum < 0X80000000)){
                    sum = 0;
                    break;
                }
                
            }
            return fuhao ? sum : sum * -1;
        }
    }
    

    声明:此文章为本人原创,如有转载,请注明出处

    如果您觉得有用,欢迎关注我的公众号,我会不定期发布自己的学习笔记、AI资料、以及感悟,欢迎留言,与大家一起探索AI之路。

    AI探索之路

    相关文章

      网友评论

          本文标题:剑指Offer(java答案)(41-50)

          本文链接:https://www.haomeiwen.com/subject/papazqtx.html