本篇博客主要为了就腾讯2017年暑期实习生编程题做一个题解,和大家进行简单分享,也为了自己对基础算法的巩固。
1.构造回文
本题题目描述如上图,该题只需要进行稍微转化一下就是我们常见的算法题,首先最少需要删除字符,即求原序列的最大回文子序列(可不连续),那么最大回文子序列又可以转化为lcs问题,即原序列与逆序列的lcs问题。
代码实现:
import java.util.*;
public class MakingPalindromic {
public static int lcs(String s1,String s2)
{
int[][] res=new int[s1.length()+1][s2.length()+1];
int x=0;
for(int i=1;i<=s1.length();i++)
{
for(int j=1;j<=s2.length();j++)
{
if(s1.charAt(i-1)==s2.charAt(j-1))
x=1;
else
x=0;
res[i][j]=Math.max(res[i-1][j-1]+x, Math.max(res[i-1][j], res[i][j-1]));
}
}
return res[s1.length()][s2.length()];
}
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner sc=new Scanner(System.in);
while(sc.hasNextLine())
{
String s1=sc.nextLine();
StringBuffer sb=new StringBuffer(s1);
sb.reverse();
String s2=""+sb;
int ans=s1.length()-lcs(s1,s2);
System.out.println(ans);
}
}
}
2.算法基础--字符移位
本题的一个主要难点便是不能申请额外的空间。因为要求大写字母放到后面,小写字母放前面,且各个字符相对位置不变,那么我们可以想到的便是具有稳定性的且进行原地排序的排序算法,这里我选择的是插入排序。但是对于字符串来说如何在不申请额外空间的情况下实现插入排序呢,因为string是不可变更的,因此这里我使用的是stringbuffer类,而stringbuffer类的setCharAt(int index,char ch)方法可以实现移位。所以,代码如下:
代码实现:
import java.util.*;
public class CharMove {
public static StringBuffer insertSort(StringBuffer s)
{
int n=s.length();
for(int i=1;i<n;i++)
{
char v=s.charAt(i);
int j=i;
if(s.charAt(j)>='a'&&s.charAt(j)<='z')
{
while(j>=1&&(s.charAt(j-1)>='A'&&s.charAt(j-1)<='Z'))
{
s.setCharAt(j, s.charAt(j-1));
j--;
}
}
s.setCharAt(j, v);
}
return s;
}
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner sc=new Scanner(System.in);
while(sc.hasNextLine())
{
StringBuffer sb=new StringBuffer(sc.nextLine());
System.out.println(insertSort(sb));
}
}
}
另外,还有一种更简答的思路,即字符串匹配的方法,因为前面全部为小写,后面全部为大写,所以只需匹配小写的加上匹配大写的合并即可,这里匹配采用relaceAll,首先将大写的全部用""替换,然后将小写的用空字符串替换,再将两者加上即可。
代码实现:
import java.util.*;
public class CharMove {
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner sc=new Scanner(System.in);
while(sc.hasNextLine())
{
String s=sc.nextLine();
System.out.println(s.replaceAll("[A-Z]", "")+""+s.replaceAll("[a-z]", ""));
}
}
}
3.有趣的数字
本题需要将问题都各种情况先列清楚
* 1.所有数字都一样,那么只需要输出n*(n-1)/2即可
* 2.最大差就是最小值的个数乘以最大值的个数,所以这里用了hashmap用于统计各个参数的个数
* 最小差又需要分为两种情况:1,元素都互异,则只需将序列排序,然后求出相邻差值,找出最小值,并查看个数即可,2.元素有相同的,遍历hashmap,并用q统计个数
* 若有元素个数l大于1,则q+=(l-1)*l/2.
* 最终输出最小差最大差即可
* 1.所有数字都一样,那么只需要输出n*(n-1)/2即可
* 2.最大差就是最小值的个数乘以最大值的个数,所以这里用了hashmap用于统计各个参数的个数
* 最小差又需要分为两种情况:1,元素都互异,则只需将序列排序,然后求出相邻差值,找出最小值,并查看个数即可,2.元素有相同的,遍历hashmap,并用q统计个数
* 若有元素个数l大于1,则q+=(l-1)*l/2.
* 最终输出最小差最大差即可
代码实现:
import java.util.*;
public class InterestingNum {
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner sc=new Scanner(System.in);
while(sc.hasNext())
{
int n=Integer.parseInt(sc.nextLine());
int[] res=new int[n];
String[] s1=sc.nextLine().split(" ");
for(int i=0;i<n;i++)
{
res[i]=Integer.parseInt(s1[i]);
}
Arrays.sort(res);
if(res[0]==res[n-1])//如果全部元素相等,则只需输出n*(n-1)/2即可。
System.out.println(n*(n-1)/2);
else
{
Map map=new HashMap();//用hashmap统计各元素的个数
for(int i=0;i<n;i++)
{
if(map.containsKey(res[i]))
map.put(res[i], (int)map.get(res[i])+1);
else
map.put(res[i], 1);
}
Object[] a=map.keySet().toArray();//hashmap的key值列表。
Arrays.sort(a);//对hashmap的key值进行排序,即原列表产生的集合序列。
int q=0;
//首先求最小差,需要考虑两个方面:a.hashmap中所有value值都为1,即原序列元素都互异。
//这需要对key值列表求相邻两个元素的差,并找到最小值的个数,即题目要求的最小差的个数。
//b.若原序列有相同元素,则需要对hashmap进行遍历,求出可能的组合,即最小差个数
boolean flag=false;
for(int j=0;j<a.length;j++)
{
int tmp=(int)map.get(a[j]);
if(tmp>1)
{
flag=true;
q+=(tmp-1)*tmp/2;
}
}
ArrayList list=new ArrayList();
for(int j=1;j<a.length;j++)
{
int p=(int)a[j]-(int)a[j-1];
list.add(p);
}
Collections.sort(list);
if(!flag)
{
for(int i=0;i<list.size();i++)
{
if(list.get(i)==list.get(0))
q+=1;
}
}
//最大差即求出hashmap中最大key值和最小key值所对应的value值即可
int t1=(int)map.get(a[0]);
int t2=(int)map.get(a[a.length-1]);
int max_num=t1*t2;
System.out.println(q+" "+max_num);
}
}
}
}
如果大家发现我分析有误的,随时可以跟我提出,万分感谢。