剑指Offer算法题及答案Java完整版(三)

31、给定一个数组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]。不能使用除法。

package cn.ctgu.offer;
/*
 * 题目:
 * 给定一个数组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]。不能使用除法。
 * 
 * 思路:
 * 1、B[i]=A[0]*A[1]*...*A[i-1]*A[i+1]*...*A[n-1]
 * 2、从左到右算 B[i]=A[0]*A[1]*...*A[i-1]
 * 3、从右到左算B[i]*=A[i+1]*...*A[n-1]
 * 

 * 解释下代码,设有数组大小为5。
 * 对于第一个for循环
 * 第一步:b[0] = 1;
 * 第二步:b[1] = b[0] * a[0] = a[0]
 * 第三步:b[2] = b[1] * a[1] = a[0] * a[1];
 * 第四步:b[3] = b[2] * a[2] = a[0] * a[1] * a[2];
 * 第五步:b[4] = b[3] * a[3] = a[0] * a[1] * a[2] * a[3];
 * 
 * 然后对于第二个for循环
 * 第一步
 * b[4]=b[4] *ret= b[4];
 * ret=ret*a[4]=a[4]
 * 
 * 第二步
 * b[3]=b[3]*ret=b[3] * a[4];
 * ret=ret*a[3]=a[4]*a[3]
 * 
 * 第三步
 * b[2]=b[2]*ret=a[0]*a[1]*a[4]*a[3]; 
 * ret=ret*[a2]=a[4]*a[3]*[a2]
 * 
 * 第四步
 * b[1]=b[1]*ret=a[0]*a[4]*a[3]*a[2]; 
 * ret=ret*a[1]=a[4]*a[3]*a[2]*a[1]
 * 
 * 第五步
 * b[0]=b[0]*ret=1*a[4]*a[3]*a[2]*a[1]=a[4]*a[3]*a[2]*a[1]
 * ret=a[4]*a[3]*a[2]*a[1]*a[0]
 *  * */
public class Mulitp {
    public int[] multiply(int[] A) {
        int n=A.length;
        int[]b=new int[n];
        int ret=1;
        for(int i=0;i<n;i++) {
            b[i]=ret;
            ret=ret*A[i];
        }
        ret=1;
        for(int i=n-1;i>=0;i--) {
            b[i]=b[i]*ret;
            ret=ret*A[i];
        }
        return b;
    }
}

32、输入一个整数,输出该数二进制表示中1的个数。其中负数用补码表示。

package cn.ctgu.offer;

import java.util.LinkedList;

/*
 * 输入一个整数,输出该数二进制表示中1的个数。其中负数用补码表示。
 * 
 * 思路:
 * 1、先判断其是否为负数,如果为负数则将其转化为补码
 * 2、如果为正数则将其转换为二进制表示的数,并将其存在int类型数组中
 * 3、用0xFF与该数做异或运算,相同为0,不同为1,并将结果存在数组中,计算出为0的个数也就是1的个数
 * 
 * 
 * */
public class OneInNumber {
     public int NumberOf1(int n) {
        int count=0;
        if(n>0) {
            String nums=getBinary(n);
            for(int i=0;i<nums.length();i++) {
                 if(nums.charAt(i)=='1') {
                     count+=1;
                 }
             }
        }else {
             int t=0;
             StringBuilder sb=new StringBuilder();
             for (int i = 0; i < 32; i++)
                {
                    // 0x80000000 是一个首位为1,其余位数为0的整数
                    t = (n & 0x80000000 >>> i) >>> (31 - i); //负数的补码
                    sb.append(t);
                }
             String nums=sb.toString();
             for(int i=0;i<nums.length();i++) {
                 if(nums.charAt(i)=='1') {
                     count+=1;
                 }
             }
         }
        return count;
}
     //该函数主要用于将十进制数转为二进制数
     public static String getBinary(int num) {
         int currentNum=num;
         LinkedList<String>list=new LinkedList<String>();
         while(currentNum!=0) {
             if(currentNum%2==0) {
                 list.addFirst("0");
             }else {
                 list.addFirst("1");
             }
             currentNum/=2;
         }
         StringBuilder sb=new StringBuilder();
         for(int i=0;i<list.size();i++) {
             sb.append(list.get(i));
         }
         return sb.toString();
     }
     //这个最简单
     public int NumberOf2(int n) {
            int t=0;
                char[]ch=Integer.toBinaryString(n).toCharArray();
                for(int i=0;i<ch.length;i++){
                    if(ch[i]=='1'){
                        t++;
                    }
                }
                return t;
        }
     /*
      *  如果一个整数不为0,那么这个整数至少有一位是1。如果我们把这个整数减1,那么原来处在整数最右边的1就会变为0,原来在1后面的所有的0都会变成1(如果最右边的1后面还有0的话)。
      *  其余所有位将不会受到影响。
        举个例子:一个二进制数1100,从右边数起第三位是处于最右边的一个1。减去1后,第三位变成0,它后面的两位0变成了1,而前面的1保持不变,因此得到的结果是1011.
        我们发现减1的结果是把最右边的一个1开始的所有位都取反了。
        这个时候如果我们再把原来的整数和减去1之后的结果做与运算,从原来整数最右边一个1那一位开始所有位都会变成0。
        如1100&1011=1000.也就是说,把一个整数减去1,再和原整数做与运算,会把该整数最右边一个1变成0.那么一个整数的二进制有多少个1,就可以进行多少次这样的操作。 
      * */
      public int NumberOf3(int n) {
            int count = 0;
            while(n!= 0){
                count++;
                n = n & (n - 1);
             }
            return count;
        }

     public static void main(String[]args) {
         OneInNumber num=new OneInNumber();
         System.out.println(num.NumberOf1(-2147483648));
         /*for (int i = 0; i < 32; i++)
            {
                // 0x80000000 是一个首位为1,其余位数为0的整数
                int t = (-2147483648 & 0x80000000 >>> i) >>> (31 - i); //负数的补码
                System.out.println(t);
            }*/
     }
}

33、输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字,例如,如果输入如下4 X 4矩阵: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 则依次打印出数字1,2,3,4,8,12,16,15,14,13,9,5,6,7,11,10.

package cn.ctgu.offer;

import java.util.ArrayList;
/*
 * 
 * 输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字,
 * 例如,如果输入如下矩阵: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 
 * 则依次打印出数字1,2,3,4,8,12,16,15,14,13,9,5,6,7,11,10.
 * 
 * 思路:
 * 1、每一圈从左到右,从上到下,然后从右到左,从下到上
 * 2、当从右到左的时候需要判断舍掉对右下角的元素(因为从上到下已经打印了)
 * 3、当从下到上的时候需要舍掉左上角的元素(因为从左到右已经打印了)
 * 4、终止条件为top==bottom right==left
 * 
 * */
import java.util.Iterator;

public class PrintMatrix {
    public ArrayList<Integer> printMatrix(int [][] matrix) {
       int rows=matrix.length;
       int columns=matrix[0].length;
       int top=0;
       int bottom=rows-1;
       int left=0;
       int right=columns-1;
       ArrayList<Integer>array=new ArrayList<Integer>();
       if(rows==0||columns==0) {
           return null;
       }
       while(top<=bottom&&left<=right) {
           for(int i=left;i<=right;i++) {
               array.add(matrix[top][i]);//从左到右打印
           }
           for(int j=top+1;j<=bottom;j++) {
               array.add(matrix[j][right]);//从上到下打印
           }
           if(top!=bottom) {                    //考虑只有一行的情况
               for(int i=right-1;i>=left;i--) {
                   array.add(matrix[bottom][i]);//从右到左打印
               }
           }
           if(right!=left) {                    //考虑只有一列的情况
               for(int j=bottom-1;j>=top+1;j--) {
                   array.add(matrix[j][left]);//从下到上打印
               }
           }
           left++;
           right--;
           top++;
           bottom--;
       }
       return array;
    }
    public static void main(String[]args) {
        int[][]matrix= {{1,2,3,4},{5,6,7,8},{9,10,11,12},{13,14,15,16},{17,18,19,20}};
        PrintMatrix print=new PrintMatrix();
        ArrayList<Integer> array=new ArrayList<Integer>();
        array=print.printMatrix(matrix);
        Iterator<Integer> it=array.iterator();
        while(it.hasNext()){
            System.out.println(it.next());
        }
    }
}

34、输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否为该栈的弹出顺序。假设压入栈的所有数字均不相等。例如序列1,2,3,4,5是某栈的压入顺序,序列4,5,3,2,1是该压栈序列对应的一个弹出序列,但4,3,5,1,2就不可能是该压栈序列的弹出序列。(注意:这两个序列的长度是相等的)

package cn.ctgu.offer;
import java.util.ArrayList;
/*
 * 输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否为该栈的弹出顺序。
 * 假设压入栈的所有数字均不相等。
 * 例如序列1,2,3,4,5是某栈的压入顺序
 * 序列4,5,3,2,1是该压栈序列对应的一个弹出序列
 * 但4,3,5,1,2就不可能是该压栈序列的弹出序列。
 * (注意:这两个序列的长度是相等的)
 * 
 * 思路:
 * 1、当两个长度不相等时则返回false
 * 2、当长度为1,值不相等时返回false
 * 3、小于第一个弹出的元素的所有索引必须是顺序的,没必要紧挨,但一定得保持前后顺序
 * 
 * 
 * */
public class PushAndPopStack {
     public boolean IsPopOrder(int [] pushA,int [] popA) {
         boolean flag=true;
         if(pushA.length!=popA.length) {
             flag=false;
             return flag;
         }
         if(pushA.length==1) {
             if(pushA[0]==popA[0]) {
                 return flag;
             }else {
                 flag=false;
                 return flag;
             }
         }
         ArrayList<Integer>array=new ArrayList<Integer>();
         int index=Find(pushA,popA[0]);
         int j=0;
         if(index==-1) {
             flag=false;
             return flag;
         }else {
             for(int i=0;i<index;i++) {
                 array.add(Find(popA,pushA[i]));//找出所有小于第一个出栈元素的索引,当这些索引不是递增关系则不可能是该压栈的弹出序列
             }
             while(j!=(array.size()-1)) {
                 if(array.get(j)<array.get(j+1)) {
                     flag=false;
                     return flag;
                 }else {
                     j++;
                 }
             }
         }
         return flag;
     }
     //查找弹出的第一个元素在栈中的位置
     public int Find(int [] pushA,int target) {
        int i=0;
        while(target!=pushA[i]&&i<pushA.length) {
            i++;
        }
        return i;
     }
     public static void main(String[]args) {
         int[]pushA={1,2,3,4,5};
         int[]popA={4,5,3,2,1};
         int[]popB={4,3,5,1,2};
         int[]pushOne= {1};
         int[]popOne= {2};
         PushAndPopStack stack=new PushAndPopStack();
         if(stack.IsPopOrder(pushA, popA)) {
             System.out.println("popA是弹出序列");
         }else {
             System.out.println("popA不是弹出序列");
         }
         if(stack.IsPopOrder(pushA, popB)) {
             System.out.println("popB是弹出序列");
         }else {
             System.out.println("popB不是弹出序列");
         }
        if(stack.IsPopOrder(pushOne, popOne)) {
             System.out.println("popB是弹出序列");
         }else {
             System.out.println("popB不是弹出序列");
         }
     }
}
链接:https://www.nowcoder.com/questionTerminal/d77d11405cc7470d82554cb392585106
来源:牛客网

/*思路:先循环将pushA中的元素入栈,遍历的过程中检索popA可以pop的元素
**如果循环结束后栈还不空,则说明该序列不是pop序列。
**文字有点难说明白,看代码。
*/
import java.util.ArrayList;
import java.util.Stack;
public class Solution {
    public boolean IsPopOrder(ArrayList<Integer> pushA,ArrayList<Integer> popA) {
        Stack stack = new Stack();
        if( pushA.size() == 0 && popA.size() == 0 ) return true;
        for( int i=0,j=0; i < pushA.size(); i++ ){
            stack.push( pushA.get(i) );
            while( ( !stack.empty() )&& ( stack.peek() == popA.get(j) ) ){
                stack.pop();
                j ++;
            } 
        }

        return stack.empty() == true;
    }
}

35、在一个长度为n的数组里的所有数字都在0到n-1的范围内。数组中某些数字是重复的,但不知道有几个数字是重复的。也不知道每个数字重复几次。请找出数组中任意一个重复的数字。例如,如果输入长度为7的数组{2,3,1,0,2,5,3},那么对应的输出是第一个重复的数字2。

package cn.ctgu.offer;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Random;

/*
 * 题目:
 * 在一个长度为n的数组里的所有数字都在0到n-1的范围内。
 * 数组中某些数字是重复的,但不知道有几个数字是重复的。
 * 也不知道每个数字重复几次。请找出数组中任意一个重复的数字。
 * 例如,如果输入长度为7的数组{2,3,1,0,2,5,3},
 * 那么对应的输出是第一个重复的数字2。
 * 
 * 思路:
 * 1、采用hashMap
 * 2、统计每个数字出现的次数
 * 3、输出第一个串重复的数字
 * 
 * */
public class RepeatNumber {
    public boolean duplicate(int numbers[],int length,int [] duplication) {
        Map<Integer,Integer>map=new HashMap<Integer,Integer>();
        for(int i=0;i<length;i++) {
            int key=numbers[i];
            int count=0;
            for(int j=0;j<length;j++) {
                if(key==numbers[j]) {
                    count=count+1;
                }
            map.put(key, count);
            }
        }
        Iterator<Map.Entry<Integer,Integer>>iter=map.entrySet().iterator();
        ArrayList<Integer>data=new ArrayList<Integer>();
        while(iter.hasNext()) {
            Map.Entry<Integer,Integer>entry=iter.next();
            if(entry.getValue()>=2) {
                data.add(entry.getKey());
            }
        }
        Random rand=new Random();
        if(data.size()>0) {
            int index=rand.nextInt(data.size());
            duplication[0]=data.get(index);
            return true;
        }else {
            return false;
        }

    }
}




/*import java.util.*;
public class Solution {   
public boolean duplicate(int numbers[],int length,int [] duplication) {
//方法1if(numbers == null || numbers.length == 0) return false;
        Arrays.sort(numbers);
        int flag = 0;//做标记
        for(int i=0;i<length-1;i++) {
            if(numbers[i] == numbers[i+1]) {
                duplication[0] = numbers[i];
                flag = 1;
                break;
            }
        }
        return flag == 1? true:false;
//方法2:
        HashSet<Integer> hs = new HashSet<>();
        for(int i=0;i<length;i++) {
            if(!hs.add(numbers[i])) {
                duplication[0]=numbers[i];
                return true;
            }
        }
        return false;
    }
}*/

36、请实现一个函数,将一个字符串中的空格替换成“%20”。例如,当字符串为We Are Happy.则经过替换之后的字符串为We%20Are%20Happy。

package cn.ctgu.offer;
/*
 * 请实现一个函数,将一个字符串中的空格替换成“%20”。
 * 例如,当字符串为We Are Happy.则经过替换之后的字符串为We%20Are%20Happy。
 * 
 * */
public class ReplaceBlank {
    /*
     * 依次获取StringBuffer中的每一个字符,当它为空格的时候则将其替换成字符串"%20"
     * 注意:当我们替换成字符串之后,StringBuffer中的字符会自动往后移,长度也会自动增加
     * 
     * */
    public String replaceSpace(StringBuffer str) {

        for(int i=0;i<=str.length()-1;i++) {
                if(str.charAt(i)==' ') {
                    str.replace(i, i+1, "%20");//它会把"20%"当做一个子串插入进去,所以是i+1而不是i+3
                    i=i+2;
                }
        }
        return str.toString();
    }
    public static void main(String[] args) {
        ReplaceBlank replaceBlank=new ReplaceBlank();
        StringBuffer st=new StringBuffer("hello   world ");
        String s=replaceBlank.replaceSpace(st);
        System.out.println(s);
    }
}

37、牛客最近来了一个新员工Fish,每天早晨总是会拿着一本英文杂志,写些句子在本子上。同事Cat对Fish写的内容颇感兴趣,有一天他向Fish借来翻看,但却读不懂它的意思。例如,“student. a am I”。后来才意识到,这家伙原来把句子单词的顺序翻转了,正确的句子应该是“I am a student.”。

package cn.ctgu.offer;
/*
 * 题目:
 * 牛客最近来了一个新员工Fish,每天早晨总是会拿着一本英文杂志,写些句子在本子上。
 * 同事Cat对Fish写的内容颇感兴趣,有一天他向Fish借来翻看,但却读不懂它的意思。
 * 例如,“student. a am I”。
 * 后来才意识到,这家伙原来把句子单词的顺序翻转了,正确的句子应该是“I am a student.”。
 * 
 * 
 * 思路:
 * 1、按空格将字符串切割成字符串数组
 * 2、倒序
 * 
 * 
 * */
public class ReverseSenten {
    public String ReverseSentence(String str) {
        if(str.length()==0) {
            return "";
        }
        if(str.trim().equals("")) {
            return str;
        }
        String[]arr=str.split("\\s+");
        String s="";
        for(int i=arr.length-1;i>=0;i--) {
            s=s+" "+arr[i];
        }
        return s.trim();
    }
    public static void main(String[]args) {
        ReverseSenten solution=new ReverseSenten();
        String str="student. a am I";
        String s=solution.ReverseSentence(str);
        System.out.println(s);
    }
}

38、把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。输入一个非递减排序的数组的一个旋转,输出旋转数组的最小元素。例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组的最小值为1。 NOTE:给出的所有元素都大于0,若数组大小为0,请返回0。

package cn.ctgu.offer;
/*
 * 把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。
 * 输入一个非递减排序的数组的一个旋转,输出旋转数组的最小元素。 
 * 例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组的最小值为1。 
 * NOTE:给出的所有元素都大于0,若数组大小为0,请返回0。
 * 
 * */
public class RotateArray {
    public int[] minNumberInRotateArray(int [] array) {
        int j=0;
        int []tempArray=new int[array.length];
        if(array.length==0) {
            array[0]=0;
            return array;
        }
        if(array.length==1) {
            return array;
        }else {
            for(int i=0;i<=array.length-3;i++) {
                if(array[i]>array[i+1]&&array[i+1]<array[i+2]) {
                    j=i+1;//j元素为数组中最小的一个数
                }
            }
            int len=array.length-j;
            int []pre=new int[j];
            int []back=new int[len];
            for(int i=0;i<=j-1;i++) {
                pre[i]=array[i];
            }
            for(int k=j;k<=array.length-1;k++) {
                back[k-j]=array[k];
            }
            for(int temp=0;temp<=pre.length-1;temp++) {
                tempArray[len+temp]=pre[temp];
            }
            for(int b=0;b<=back.length-1;b++) {
                tempArray[b]=back[b];
            }
        }
        return tempArray;
    }
    public static void main(String[]args) {
        RotateArray rotateArray=new RotateArray();
        int[] array={1,1,1,1,1};
        int[]temp=new int[array.length];
        temp=rotateArray.minNumberInRotateArray(array);
        System.out.println(array[0]);
        System.out.println("--------------------------");
        for(int i=0;i<=array.length-1;i++) {
            System.out.println(temp[i]);
        }

    }
}

39、输入一个字符串,按字典序打印出该字符串中字符的所有排列。例如输入字符串abc,则打印出由字符a,b,c所能排列出来的所有字符串abc,acb,bac,bca,cab和cba。

package cn.ctgu.offer;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/*
 * 输入一个字符串,按字典序打印出该字符串中字符的所有排列。
 * 例如输入字符串abc,则打印出由字符a,b,c所能排列出来的所有字符串abc,acb,bac,bca,cab和cba。
 * 
 * 
 * 思路:
 * 1、将字符串转成字符串数组
 * 2、字符串数组进行排列组合
 * 3、将排列组合后的字符串数组转成字符串
 * 4、比较字符串大小
 * */
public class SortString {
    public ArrayList<String> Permutation(String str) {
        List<String> resultList = new ArrayList<>();
        if(str.length() == 0)
            return (ArrayList)resultList;
        //递归的初始值为(str数组,空的list,初始下标0)
        fun(str.toCharArray(),resultList,0);
        Collections.sort(resultList);
        return (ArrayList)resultList;
    }

    private void fun(char[] ch,List<String> list,int i){
        //这是递归的终止条件,就是i下标已经移到char数组的末尾的时候,考虑添加这一组字符串进入结果集中
        if(i == ch.length-1){
            //判断一下是否重复
            if(!list.contains(new String(ch))){
                list.add(new String(ch));
                return;
            }
        }else{
            //这一段就是回溯法,这里以"abc"为例

            //递归的思想与栈的入栈和出栈是一样的,某一个状态遇到return结束了之后,会回到被调用的地方继续执行

            //1.第一次进到这里是ch=['a','b','c'],list=[],i=0,我称为 状态A ,即初始状态
            //那么j=0,swap(ch,0,0),就是['a','b','c'],进入递归,自己调自己,只是i为1,交换(0,0)位置之后的状态我称为 状态B 
            //i不等于2,来到这里,j=1,执行第一个swap(ch,1,1),这个状态我称为 状态C1 ,再进入fun函数,此时标记为T1,i为2,那么这时就进入上一个if,将"abc"放进list中
            /////////////-------》此时结果集为["abc"]

            //2.执行完list.add之后,遇到return,回退到T1处,接下来执行第二个swap(ch,1,1),状态C1又恢复为状态B
            //恢复完之后,继续执行for循环,此时j=2,那么swap(ch,1,2),得到"acb",这个状态我称为C2,然后执行fun,此时标记为T2,发现i+1=2,所以也被添加进结果集,此时return回退到T2处往下执行
            /////////////-------》此时结果集为["abc","acb"]
            //然后执行第二个swap(ch,1,2),状态C2回归状态B,然后状态B的for循环退出回到状态A

            //             a|b|c(状态A)
            //               |
            //               |swap(0,0)
            //               |
            //             a|b|c(状态B)
            //             /  \
            //   swap(1,1)/    \swap(1,2)  (状态C1和状态C2)
            //           /      \
            //         a|b|c   a|c|b

            //3.回到状态A之后,继续for循环,j=1,即swap(ch,0,1),即"bac",这个状态可以再次叫做状态A,下面的步骤同上
            /////////////-------》此时结果集为["abc","acb","bac","bca"]

            //             a|b|c(状态A)
            //               |
            //               |swap(0,1)
            //               |
            //             b|a|c(状态B)
            //             /  \
            //   swap(1,1)/    \swap(1,2)  (状态C1和状态C2)
            //           /      \
            //         b|a|c   b|c|a

            //4.再继续for循环,j=2,即swap(ch,0,2),即"cab",这个状态可以再次叫做状态A,下面的步骤同上
            /////////////-------》此时结果集为["abc","acb","bac","bca","cab","cba"]

            //             a|b|c(状态A)
            //               |
            //               |swap(0,2)
            //               |
            //             c|b|a(状态B)
            //             /  \
            //   swap(1,1)/    \swap(1,2)  (状态C1和状态C2)
            //           /      \
            //         c|b|a   c|a|b

            //5.最后退出for循环,结束。

            for(int j=i;j<ch.length;j++){
                swap(ch,i,j);
                fun(ch,list,i+1);
                swap(ch,i,j);
            }
        }
    }

    //交换数组的两个下标的元素
    private void swap(char[] str, int i, int j) {
            if (i != j) {
                char t = str[i];
                str[i] = str[j];
                str[j] = t;
            }
        }   
}

40、 将一个字符串转换成一个整数(实现Integer.valueOf(string)的功能,但是string不符合数字要求时返回0),要求不能使用字符串转换整数的库函数。 数值为0或者字符串不是一个合法的数值则返回0。

package cn.ctgu.offer;
/*
 * 题目:
 * 将一个字符串转换成一个整数(实现Integer.valueOf(string)的功能,但是string不符合数字要求时返回0)
 * 要求不能使用字符串转换整数的库函数。 数值为0或者字符串不是一个合法的数值则返回0。
 * 
 * 输入描述:
 * 输入一个字符串,包括数字字母符号,可以为空
 * +2147483647
    1a33

 * 输出描述:  
 * 如果是合法的数值表达则返回该数字,否则返回0
 * 2147483647
 *  0
 *  
 * 思路:
 * 1、处理+、-,如果为+则最终的结果乘以1,否则乘以-1
 * 2、判断是否合法
 * 
 * 
 * */
public class String2Int {
    public int StrToInt(String str) {
        char[]strArray=str.toCharArray();
        if(str.isEmpty()) {
            return 0;
        }
        int symbol=1;
        if(strArray[0]=='-') {//处理负号
            symbol=-1;
            strArray[0]='0';//之所以要将strArray[0]置位'0'是方便后面进行strArray[i]-'0'运算
        }else if(strArray[0]=='+') {//处理正号
            symbol=1;
            strArray[0]='0';
        }
        int sum=0;
        for(int i=0;i<strArray.length;i++) {
            if(strArray[i]<'0'||strArray[i]>'9') {
                sum=0;
                break;
            }
            sum=sum*10+strArray[i]-'0';//数字与数字的Ascii码是连着的,数字与它们相加减其实是与其Ascii码相加减的,但是Ascii码的差值和实际数字的差值是个固定,所以可行
        }
        return symbol*sum;
    }
    public static void main(String[]args) {
        System.out.println(1+'2');//51
        System.out.println(51-'1');//2;与字符相加减实际上是与字符的Ascii码相加减,字符先转成int型然后执行加减运算的
        System.out.println("2"+1);//结果21
        System.out.println(1+"2");//12
    }
}

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

package cn.ctgu.offer;
/*
 * 题目:
 * 写一个函数,求两个整数之和,要求在函数体内不得使用+、-、*、/四则运算符号。
 * 
 * 思路:
 * 1、用位运算
 * 2、首先看十进制是如何做的: 5+7=12,三步走
 * 3、相加各位的值,不算进位(用异或运算)
 *    相加各位的值,不算进位,得到010,二进制每位相加就相当于各位做异或操作,101^111。得到2,二进制每位相加就相当于各位做异或操作,101^111=010
 * 
 * 4、计算进位值(用与运算,然后左移一位),得到10,如果这一步的进位值为0,那么第一步得到的值就是最终结果
 *     计算进位值,得到1010,相当于各位做与操作得到101,再向左移一位得到1010,(101&111)<<1。
 * 
 * 5、否则重复上述两步,只是相加的值变成上述两步得到的结果2和10,得到12
 * 
 * 
 * */
public class TwoNumberAdd {
    public int Add(int num1,int num2) {
        while(num2!=0) {
            int temp=num1^num2;
            num2=(num1&num2)<<1;
            num1=temp;
        }
        return num1;
    }
}

42、把只包含质因子2、3和5的数称作丑数(Ugly Number)。例如6、8都是丑数,但14不是,因为它包含质因子7。惯上我们把1当做是第一个丑数。求按从小到大的顺序的第N个丑数。

package cn.ctgu.offer;
/*
 * 题目:
 * 把只包含质因子2、3和5的数称作丑数(Ugly Number)。
 * 例如6、8都是丑数,但14不是,因为它包含质因子7。
 *  习惯上我们把1当做是第一个丑数。求按从小到大的顺序的第N个丑数。
 * 
 * 思路:
 * 1、丑数的定义是1或者只有2、3、5可推出丑数=丑数*丑数
 *   假定丑数有序序列为:a1,a2,a3.......an 所以可以将以上序列(a1除外)可以分成3类
 * 2、必定满足: 包含2的有序丑数序列:2*a1, 2*a2, 2*a3 ..... 
 *              包含3的有序丑数序列:3*a1, 3*a2, 3*a3 ..... 
 *                    包含5的有序丑数序列:5*a1, 5*a2, 5*a3 ..... 以上3个序列的个数总数和为n个
 * 3、而且已知a1 = 1了,将以上三个序列合并成一个有序序列即可 
 * 
 * 
 * */
public class UglyNumber {
    public int GetUglyNumber_Solution(int index) {
        int []arr = new int [index];
        if(index==0)
            return 0;
        arr[0]=1;
        int t2=0,t3=0,t5=0; //第一个丑数为1,放入数组第一个元素
      for(int i=1;i<index;i++)
      {
        //通过1依次乘2,3,5找到后面的丑数,再通过找到的丑数依次乘2,3,5找到后面的,排序即可
          arr[i]=Math.min(arr[t2]*2,Math.min(arr[t3]*3,arr[t5]*5));
           if(arr[t2]*2==arr[i])
               t2++;
           if(arr[t3]*3==arr[i])
               t3++;
           if(arr[t5]*5==arr[i])
               t5++;
      }
        return arr[index-1];
    }


}
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值