剑指offer(40-43)

第40题

题目描述: 小明很喜欢数学,有一天他在做数学作业时,要求计算出9~16的和,他马上就写出了正确答案是100。但是他并不满足于此,他在想究竟有多少种连续的正数序列的和为100(至少包括两个数)。没多久,他就得到另一组连续正数和为100的序列:18,19,20,21,22。现在把问题交给你,你能不能也很快的找出所有和为S的连续正数序列? Good Luck!

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

思路描述: 首先肯定可以通过两次遍历,找出所有满足条件的序列,这样的方式时间复杂度较高,不能通过。下面介绍的方法通过两个指针构成了一个滑动的窗口。如果窗口内的序列和等于100,则是一个满足要求的序列。根据序列和与100的关系,调整两个指针。

代码如下:

import java.util.ArrayList;
public class Solution {
    public ArrayList<ArrayList<Integer> > FindContinuousSequence(int sum) {
        //记录最后的结果
        ArrayList<ArrayList<Integer>> result = new ArrayList<ArrayList<Integer>>();
        //两个指示位置的指针
        int lowIndex = 1;
        int highIndex = 2;
        while(lowIndex < highIndex){
            //计算出当前窗口的和(满足等差数列)
            int cur = (lowIndex + highIndex)*(highIndex - lowIndex + 1)/2;
            //符合要求
            if(cur == sum){
                ArrayList<Integer> list = new ArrayList<Integer>();
                for(int i=lowIndex;i<=highIndex;i++){
                    list.add(i);
                }
                //存入
                result.add(list);
                lowIndex++;
            }else if(cur > sum){
                lowIndex++;
            }else{
                highIndex++;
            }
        }
        return result;
    }
}

第41题

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

思路分析: 首先,这道题也是能够两次递归找出满足条件的数,但是这样的复杂度较高。由于给定的序列是递增,我们应该介意通过一些方式利用这个序列递增的特性,从而提升算法的效率。可以设置头尾两个指针,则:

数列满足递增,设两个头尾两个指针i和j,
若ai + aj == sum,就是答案(相差越远乘积越小)
若ai + aj > sum,aj肯定不是答案之一(前面已得出 i 前面的数已是不可能),j -= 1
若ai + aj < sum,ai肯定不是答案之一(前面已得出 j 后面的数已是不可能),i += 1

代码如下:

import java.util.ArrayList;
public class Solution {
    public ArrayList<Integer> FindNumbersWithSum(int [] array,int sum) {
        //存储结果
        ArrayList<Integer> result = new ArrayList<Integer>();
        
        if(array == null || array.length<2){
            return result;
        }
        
        int low = 0;
        int high = array.length-1;
        
        while(low < high){
            if(array[low] + array[high] == sum){
                result.add(array[low]);
                result.add(array[high]);
                return result;
            }else if(array[low] + array[high] > sum){
                high--;
            }else{
                low++;
            }
        }
        return result;
    }
}

第42题

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

思路分析: 字符串左移n位的处理办法:前n个数做逆序,后面的数也做逆序,然后整体做逆序。

代码如下:

public class Solution {
    public String LeftRotateString(String str,int n) {
        
        if(str == null || str.length()==0){
            return new String();
        }
        
        int low = 0;
        int high = str.length();
        
        //反转前0到n-1位置元素
        StringBuilder s1 = new StringBuilder();
        for(int i = n-1;i>=0;i--){
            s1.append(str.charAt(i));
        }
        //反转n到len-1
        StringBuilder s2 = new StringBuilder();
        for(int i = high-1;i>=n;i--){
            s2.append(str.charAt(i));
        }
        
        return new StringBuffer(s1.append(s2)).reverse().toString();
    }
}

这里同时涉及到了字符串的操作,频繁地对字符串操作的话,建议使用StringBuilder。

第43题

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

思路分析: 思路较为简单,直接看代码注释即可。

代码如下:

import java.util.ArrayList;
public class Solution {
    public String ReverseSentence(String str) {
        ArrayList<String> list = new ArrayList<String>();
        int len = str.length();
        
        StringBuilder sb = new StringBuilder();
        for(int i=0;i<len;i++){
            //没有遇到空格,是一个单词
            if(str.charAt(i)!=' '){
                sb.append(str.charAt(i));
            }else{
                //将一个完整的单词存储到list中
                list.add(sb.toString());
                //清空,以便存储下一个字符单词
                sb.setLength(0);
            }
        }
        //把最后一个字符串加到list里面
        list.add(sb.toString());
        //清空
        sb.setLength(0);
        
        //从最后一个单词开始拼接,实现单词逆序
        for(int i=list.size()-1;i>=0;i--){
            sb.append(list.get(i));
            //除了最后一个单词,每个单词后面加一个空格
            if(i!=0){
                sb.append(' ');
            }
        }
        return sb.toString();
    }
}

Tips:清空StringBuilder的方式:
sb.setLength(0);
将长度置为0。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值