第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。