剑指offer(41-50)题解(一)

本文涉及的产品
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
云解析 DNS,旗舰版 1个月
全局流量管理 GTM,标准版 1个月
简介: 剑指offer(41-50)题解

41题解–和为S的连续正数序列


题目描述


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

输出描述:

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


思路解析


这道题最简单的方法就是枚举,但是这样效率很低,而且很有可能会超时,所以我们必须要做出改进。


20200807195124779.png

既然有了通项公式,那么其实我们也能推出这样一个结论,sum如果在n区间长的连续区间内满足,那么这个n区间长的区间是唯一的,不会存在第二个n长的连续区间满足,从上图我们可以看出。

其次假设刚好区间满足情况,那么区间的元素数是不是只有奇数个和偶数个这两种情况。


20200807195757987.png


这里我们得出结论当区间长度为奇数时,如果sum%区间不为0的话,那么就一定不存在这样一个区间满足

那么到了比较复杂的偶数个的情况了

偶数个的情况时就不能通过奇数的方式来解决了,这时候我们可以通过一开始的通项公式来解决。

既然我们已经确定了当前的区间长度,那么我们就可通过判断该sum是否满足通项公式就能确定是否有这样一个区间满足情况。

下面的代码注释有详细说明


源代码


import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
public class Solution {
   public int figure(int sum)
  {
    for(int i=1;i<=sum;i++)
    {
      if((i+1)*i==2*sum)
        return i;
      if((i+1)*i>2*sum)
        return i-1;
    }
    return 0;
  }
  //d表示区间长,n表示是第几个区间,然后计算总和
  public int jisuan(int d,int n)
  {
    return d*(d+1)/2+(n-1)*d;
  }
  //定义排序规则,帮助我们排序
  Comparator<ArrayList<Integer>>comparator=new Comparator<ArrayList<Integer>>() {
    @Override
    public int compare(ArrayList<Integer> o1, ArrayList<Integer> o2) {
      return o1.get(0)-o2.get(0);
    }
  };
  public ArrayList<ArrayList<Integer> > FindContinuousSequence(int sum) {
    ArrayList<ArrayList<Integer>>list=new ArrayList<ArrayList<Integer>>();
    int n=figure(sum);
    for(int i=2;i<=n;i++)
    {
      ArrayList<Integer>list2=new ArrayList<Integer>();
      list2.clear();
      //区间长为偶数时的情况
      if(i%2==0)
      {
          //计算sum与区间长为i的第一区间的差值
        int cha=sum-jisuan(i, 1);
        //如果差值刚好可以将区间长度整除就说明存在这样的连续区间,这里的区间长同时也是上述通项公式中的公差
        if(cha%i==0)
        {
          for(int j=1;j<i+1;j++)
            list2.add(j+(cha/i));
          list.add(list2);
        }
      }
      //区间长为奇数时的情况
      else 
      {
        if(sum%i==0)
        {
          int count=sum/i-i/2;
          for(int j=0;j<i;j++)
            list2.add(count+j);
          list.add(list2);  
        }
      }
    }
    Collections.sort(list, comparator);
    return list;
    }
}


42题解–和为S的两个数字


题目描述


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

输出描述:

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


思路解析


这题比较简单,只要循环查找就行了,中途记得比较保留最小乘积的两个元素即可。


源代码


import java.util.ArrayList;
public class Solution {
    public ArrayList<Integer> FindNumbersWithSum(int [] array,int sum) {
          ArrayList<Integer>list1=new ArrayList<Integer>();
          ArrayList<Integer>list2=new ArrayList<Integer>();
          int flag=Integer.MAX_VALUE;
          int num=1;
          for(int i=0;i<array.length;i++)
            list2.add(array[i]);
          for(int i=0;i<array.length;i++)
          {
            if(list2.contains(sum-array[i]))
            {
              num=(sum-array[i])*array[i];
              if(num<flag)
              {
                list1.clear();
                flag=num;
                list1.add(Math.min(sum-array[i], array[i]));
                list1.add(Math.max(sum-array[i], array[i]));
              }
            }
          }
          return list1;
      }
}


43题解–左旋转字符串


题目描述


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


思路解析


这题也比较简单只需要通过String自带的截取函数即可实现,只要注意截取函数是左闭右开的即可。


源代码


public class Solution {
    public String LeftRotateString(String str,int n) {
         String str1="";
     if(str==null)
       return str1;
     if(n>str.length())
       return str1;
       String str2=str.substring(0, n);
       String str3=str.substring(n, str.length());
       str1+=str3;
       str1+=str2;
       return str1;
   }
}


44题解–翻转单词顺序列


题目描述


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


思路解析


这里只要将整个字符串以空格为标志分割成字符数组即可,之后依次添加字符和空格即可,记得将最后一个空格取出即可。


源代码


public class Solution {
 public String ReverseSentence(String str) {
    if(str.length()==0||str==null)
            return str;
        else 
    {
      String []str1=str.split(" ");
            StringBuffer str2=new StringBuffer();
            if(str1.length==0)
                return str;
      for(int i=str1.length-1;i>-1;i--)
      {
        str2.append(str1[i]);
        str2.append(" ");
      }
      if(str2.length()>0)
        str2.deleteCharAt(str2.length()-1);
            return str2.toString();
    }
 }
}


45题解–扑克牌顺子


题目描述


LL今天心情特别好,因为他去买了一副扑克牌,发现里面居然有2个大王,2个小王(一副牌原本是54张_)…他随机从中抽出了5张牌,想测测自己的手气,看看能不能抽到顺子,如果抽到的话,他决定去买体育彩票,嘿嘿!!“红心A,黑桃3,小王,大王,方片5”,“Oh My God!”不是顺子…LL不高兴了,他想了想,决定大\小 王可以看成任何数字,并且A看作1,J为11,Q为12,K为13。上面的5张牌就可以变成“1,2,3,4,5”(大小王分别看作2和4),“So Lucky!”。LL决定去买体育彩票啦。 现在,要求你使用这幅牌模拟上面的过程,然后告诉我们LL的运气如何, 如果牌能组成顺子就输出true,否则就输出false。为了方便起见,你可以认为大小王是0。


思路解析


这题主要考察数学知识即可。

首先我们知道顺子代表的就是5个连续的数,所以这5个数各不相同的。但是又因为有大小王这种万能牌的存在,所以我们在排除0的情况下如果有相同的元素那么就一定不能构成顺子,这里大家可以先判断,不要像博主一样写在一个判断语句中。

找一下规律


20200807202919695.png


接着我们只需要对大小王的个数进行分情况讨论即可。


源代码


import java.util.Arrays;
public class Solution {
  public boolean isContinuous(int [] numbers) {
    Arrays.sort(numbers);
    if(numbers.length==0)
      return false;
    //有四张大小王这种万能牌
    if(numbers[3]==0)
      return true;
    if(numbers[2]==0&&numbers[4]-numbers[3]<=4&&numbers[4]!=numbers[3])
      return true;
    if(numbers[1]==0&&numbers[4]-numbers[2]<=4&&numbers[4]>numbers[3]&&numbers[3]>numbers[2])
      return true;
    if(numbers[0]==0&&numbers[4]-numbers[1]<=4&&numbers[4]>numbers[3]&&numbers[3]>numbers[2]&&numbers[2]>numbers[1])
      return true;
    if(numbers[4]-numbers[0]==4)
      return true;
    return false;
    }
}


相关文章
|
机器人
剑指offer(61-67)题解
剑指offer(61-67)题解
剑指offer(61-67)题解
剑指offer(19-24)题解
剑指offer(19-24)题解
剑指offer(19-24)题解
|
存储 算法