一、Z字形变换(6)
将一个给定字符串 s 根据给定的行数 numRows ,以从上往下、从左到右进行 Z 字形排列。
比如输入字符串为 “PAYPALISHIRING” 行数为 3 时,排列如下:
之后,你的输出需要从左往右逐行读取,产生出一个新的字符串,比如:“PAHNAPLSIIGYIR”。
请你实现这个将字符串进行指定行数变换的函数。
-
题目链接: link.
-
思路:创建一个集合,存放numRows个字符串,每个字符串记录每一行的字符 。定义一个移位方向flag=1或-1,当所在行在第0行或第numRows-1行时,需要改变移位方向。依次遍历字符串,将字符加入对应行的字符串。最后,依次取出各行字符串并拼接,返回变换字符串
public String convert(String s, int numRows) {
String resStr="";//返回的字符串
//创建一个集合,存放numRows个字符串,每个字符串记录每一行的字符
List<StringBuilder> rows=new ArrayList<StringBuilder>();
//初始化集合
for(int j=0;j<numRows;j++){
rows.add(new StringBuilder());
}
int flag=-1;//下移或上移标志
int i=0;//所在行
for(int j=0;j<s.length();j++){
//添加字符到对应行的字符串
rows.get(i).append(s.charAt(j));
//第0行和最后一行需要转换移动的方向;上移或下移
if(i==0||i==numRows-1){
flag=-flag;
}
//大于两行
if(numRows>=2){
i+=flag;//行上移或下移
}
}
//拼接字符串
for(StringBuilder str:rows){
resStr+=str;
}
return resStr;
}
二、整数反转(7)
给你一个 32 位的有符号整数 x ,返回将 x 中的数字部分反转后的结果。
如果反转后整数超过 32 位的有符号整数的范围 [−2^31, 2^31 − 1] ,就返回 0。
假设环境不允许存储 64 位整数(有符号或无符号)
- 题目链接:link
- 注意:本题关键:溢出判断!
public int reverse(int x) {
int res=0;//结果
while(x!=0){
int digit=x%10;//从后往前取
/********************溢出判断***************************
有符号int范围:-2147483648 ~2147483647
正数条件 : res<Integer.MAX_VALUE/10||res==Integer.MAX_VALUE/10&&num<=7
负数条件:res>Integer.MIN_VALUE/10||res==Integer.MIN_VALUE/10&&num<=8
但本题可去掉后面的判断条件。因为res==Integer.MAX_VALUE/10时,最后反转的一位必不可能大于8.int位数最大时,反转前首位数字必不可能大于2,如果大于2的话,就不能以int类型存放数据,负数同理。
**************************************************/
if(res>Integer.MAX_VALUE/10||res<Integer.MIN_VALUE/10){//数据溢出
return 0;
}
res=res*10+digit;
x/=10;//截取末尾
}
return res;
}
三、字符串转换为整数(atoi)(8)
请你来实现一个 myAtoi(string s) 函数,使其能将字符串转换成一个 32 位有符号整数(类似 C/C++ 中的 atoi 函数)
- 题目链接:link
- 注:
1、溢出判断 正/负的情况
2、特殊情况的处理 如空字符串
3、符号只判断一次
public int myAtoi(String s) {
int i=0;//下标
//while(s.charAt(i)==" ") i++;//丢弃空格
String str=s.trim();//删掉头尾的空格
int res=0;//结果
int len=str.length();//长度
//符号
char symbol='+';
//空字符串 特殊情况
if(len==0){
return 0;
}
//符号只判断一次 如果第一位是符号位,则下标一定要加1
if(str.charAt(0)=='-'||str.charAt(0)=='+'){
if(str.charAt(0)=='-'){
symbol='-';
}
//下标加1
i++;
}
//读入数字
while(i<len){
//是数字
if(str.charAt(i)>='0'&&str.charAt(i)<='9'){
int num=str.charAt(i)-'0';
//正数与负数分类讨论
if(symbol=='-'){
//溢出判断
if(res>Integer.MIN_VALUE/10||res==Integer.MIN_VALUE/10&&num<=8){
res=res*10-num;
}else{//溢出
return Integer.MIN_VALUE;
}
}else{//正数
if(res<Integer.MAX_VALUE/10||res==Integer.MAX_VALUE/10&&num<=7){
res=res*10+num;
}else{
return Integer.MAX_VALUE;
}
}
i++;//下标后移
}else{//非数字
break;
}
}
return res;
}
四、盛最多水的容器(11)
- 题目链接:link
- 方法1:暴力双循环,即遍历所有可能的情况。不推荐
- 方法2:双指针,分别指向头尾,仅遍历数组一次,即可得到最大值。
面积(容量)取决于短板。①因此即使长板往内移动时遇到更长的板,矩形的面积也不会改变;遇到更短的板时,面积会变小。②因此想要面积变大,只能让短板往内移动(因为移动方向固定了),当然也有可能让面积变得更小,但只有这样才存在让面积变大的可能性
public int maxArea(int[] height) {
//双指针
int i=0;//头
int j=height.length-1;//尾
int maxArea=0;
int temp=0;
while(i<j){
//核心 移动短板
temp=height[i]>height[j]?(j-i)*height[j--]:(j-i)*height[i++];
maxArea=Math.max(maxArea,temp);
}
return maxArea;
}
五、整数转罗马数字
- 法一:LinkedHashMap.从大到小放入键值对,保证有序
public String intToRoman(int num) {
//创建LinkedHashMap,保证存入的顺序
LinkedHashMap<Integer,String> map=new LinkedHashMap<>();
map.put(1000,"M");
map.put(900,"CM");
map.put(500,"D");
map.put(400,"CD");
map.put(100,"C");
map.put(90,"XC");
map.put(50,"L");
map.put(40,"XL");
map.put(10,"X");
map.put(9,"IX");
map.put(5,"V");
map.put(4,"IV");
map.put(1,"I");
//结果
String str=new String();
for(Integer key:map.keySet()){//遍历map
if(num==0){
break;
}
//核心 从大的开始取
while(num>=key){
num-=key;
str+=map.get(key);
}
}
return str;
}
- 法二:数组模拟LinkedHashMap
public String intToRoman(int num) {
int[] values={1000,900,500,400,100,90,50,40,10,9,5,4,1};
String[] ss={"M","CM","D","CD","C","XC","L","XL","X","IX","V","IV","I"};
String s="";
for(int i=0;i<values.length;i++){
if(num==0){
break;
}
while(num>=values[i]){
num-=values[i];
s+=ss[i];
}
}
return s;
}
六、最长公共前缀(14)
编写一个函数来查找字符串数组中的最长公共前缀。
如果不存在公共前缀,返回空字符串 “”。
示例 1:
输入:strs = [“flower”,“flow”,“flight”]
输出:“fl”
示例 2:
输入:strs = [“dog”,“racecar”,“car”]
输出:""
解释:输入不存在公共前缀。
- 题目链接:link
- 法一:暴力求解。双层循环遍历,依次比较每个字符串相同索引处的字符是否相等,直到不相等则退出。时间复杂度高。
public String longestCommonPrefix(String[] strs) {
String res="";
int n=strs.length;
int[] lens=new int[n];
int minLength=200;//最短长度
for(int i=0;i<n;i++){
lens[i]=strs[i].length();
if(minLength>lens[i]){
minLength=lens[i];
}
}
int index=0;//索引下标
boolean flag=false;
while(index<minLength){
char ch=strs[0].charAt(index);
for(int i=1;i<n;i++){
if(ch!=strs[i].charAt(index)){
flag=true;
break;
}
}
if(flag){
break;
}else{
res+=ch;
index++;
}
}
return res;
}
- 法二:(推荐)假定第一个字符串为最长公共前缀s,循环遍历每一个字符串,若字符串与s不匹配,则将s长度减1,直至所有字符串遍历结束。
public String longestCommonPrefix(String[] strs) {
if(strs.length==0){
return "";
}
String res=strs[0];//假定第一个字符串为最长公共前缀
for(String string:strs){
//不匹配,则最长公共前缀长度减1
while(!string.startsWith(res)){
if(res.length()==0){
return "";
}
res=res.substring(0,res.length()-1);
}
}
return res;
}