剑指Offer系列之题41~题45

目录
  • 41.数组中只出现一次的数字
  • 42.和为S的连续正数序列
  • 43.和为S的两个数字
  • 44.左旋转字符串
  • 45.翻转单词顺序

41.数组中只出现一次的数字

一个整型数组里除了两个数字之外,其他的数字都出现了两次。请写程序找出这两个只出现一次的数字。

暴力解:利用HashMap存储数字出现次数;

依次异或:先进行依次异或得到两个出现一次数字的异或结果,根据该结果进行分组,然后每一组进行异或得到这两个数字。


1.暴力解:

//num1,num2分别为长度为1的数组。
//将num1[0],num2[0]设置为返回结果
import java.util.Map;
import java.util.HashMap;
public class Solution {
    public void FindNumsAppearOnce(int [] array,int num1[] , int num2[]) {
        //法1:先排序,然后遍历
        //法2:辅助map存储
        Map map=new HashMap<>();
        for(int i=0;i

2.依次异或:

//num1,num2分别为长度为1的数组。传出参数
//将num1[0],num2[0]设置为返回结果
import java.util.Map;
import java.util.HashMap;
public class Solution {
    public void FindNumsAppearOnce(int [] array,int num1[] , int num2[]) {
        //方法1:先排序,然后遍历
        //方法2:辅助map存储
        //方法3:依次异或:异或的结果中,相同数字全部抵消。得到的结果是两个出现一次的数字异或的结果。
        //其中至少有一位是1,即两数字这一位不同,然后根据该位是否为1将全部数分为两组,
        //然后每一组的异或结果就是只出现一次的数
        int res=0;
        for(int i=0;i>1;
            n++;//第n位是1
        }
        for(int i=0;i>n & 1)!=1){//若该位不是1
                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的连续正数序列。序列内按照从小至大的顺序,序列间按照开始数字从小到大的顺序

双指针:左右指针从头开始(1,2),当大于和时左指针右移,小于和时,右指针右移。都向右移是为了查找所有序列


双指针:

import java.util.ArrayList;
public class Solution {
    public ArrayList > FindContinuousSequence(int sum) {
       //连续的  从小到大  至少两个数
        ArrayList> resList=new ArrayList<>();
        int low=1;//左右指针,两者都只能右移
        int high=2;
        while(high>low){
            int cur=(low+high)*(high-low+1)/2;//当前序列的和
            if(cur==sum){
                //若相等则加入列表
                ArrayList res=new ArrayList<>();
                for(int i=low;i<=high;++i){
                    res.add(i);
                }
                resList.add(res);
                //添加后移动左指针继续查找下一个序列
                low++;
            }else if(cur>sum){//若大于和,则将左指针右移,减小序列的和
                low++;
            }else if(cur

43.和为S的两个数字

输入一个递增排序的数组和一个数字S,在数组中查找两个数,使得他们的和正好是S,如果有多对数字的和等于S,输出两个数的乘积最小的。

输入描述:对应每个测试案例,输出两个数,小的先输出。

双指针,分别从前后开始遍历,大于和时右指针左移,小于和时左指针右移,第一次等于和时,即是乘积最小。


1.双指针:

import java.util.ArrayList;
public class Solution {
    public ArrayList FindNumbersWithSum(int [] array,int sum) {
        //递增排序 可能存在相等的情况
        int product=Integer.MAX_VALUE;//乘积
        int low=0;
        int high=array.length-1;
        ArrayList res=new ArrayList<>();
        if(array.length<=1)
            return res;
        while(low

2.简化版:

import java.util.ArrayList;
public class Solution {
    public ArrayList FindNumbersWithSum(int [] array,int sum) {
        //递增排序 可能存在相等的情况
        int low=0;
        int high=array.length-1;
        ArrayList res=new ArrayList<>();
        if(array.length<=1)
            return res;
        while(low

44.左旋转字符串

汇编语言中有一种移位指令叫做循环左移(ROL),现在有个简单的任务,就是用字符串模拟这个指令的运算结果。对于一个给定的字符序列S,请你把其循环左移K位后的序列输出。例如,字符序列S=”abcXYZdef”,要求输出循环左移3位后的结果,即“XYZdefabc”。是不是很简单?OK,搞定它!

暴力解:利用String的substring方法;

利用翻转特性:先翻转前n个,再翻转剩余部分,然后整体翻转,可以达到效果。


1.暴力解:

public class Solution {
    public String LeftRotateString(String str,int n) {
        //考虑str、n的异常输入
        if(n>=str.length())//移位超过字符串长度则相当于移减去字符串长度的距离
            n-=str.length();
        if(n<=0 || str.equals(""))
            return str;
        char  c[]=new char[n];
        for(int i=0;i

2.简化:

public class Solution {
    public String LeftRotateString(String str,int n) {
        //考虑str、n的异常输入
        if(n<=0 || str.equals(""))
            return str;
        if(n>=str.length())//移位超过字符串长度则相当于移减去字符串长度的距离
            n%=str.length();
        int len=str.length();
        str+=str;

        return str.substring(n,len+n);
    }
}

3.利用翻转特性:

public class Solution {
    public String LeftRotateString(String str,int n) {
        //考虑str、n的异常输入
        if(n<=0 || str.equals(""))
            return str;
        if(n>=str.length())//移位超过字符串长度则相当于移减去字符串长度的距离
            n%=str.length();
        char c[]=str.toCharArray();
        reverse(c,0,n-1);
        reverse(c,n,c.length-1);
        reverse(c,0,c.length-1);

        return new String(c);
    }

    public void reverse(char []c,int start,int end){
        while(start

45.翻转单词顺序

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

从头和尾依次交换;

或者利用StringBuilder/Buffer从尾到头添加字符串;

先翻转整个字符串,然后以空格为分割翻转单词


1.依次交换:

public class Solution {
    public String ReverseSentence(String str) {
        if(str.trim().equals(""))
            return str;
        String s[]=str.split(" ");
        int start=0;
        int end=s.length-1;
        while(start

2.整体翻转后以空格为分割翻转每个单词:

public class Solution {
    public String ReverseSentence(String str) {
        if(str.trim().equals(""))
            return str;
        char c[]=str.toCharArray();
        //先翻转整个字符串,然后以空格为界,单独翻转每个单词
        reverse(c,0,c.length-1);
        int firBlank=-1;
        for(int i =0;i

如有错误,欢迎指正

你可能感兴趣的:(剑指Offer系列之题41~题45)