咕咕咕
题目链接: 点击跳转至本题
题目大意:给定一个罗马数字,将其转换成整数。输入确保在 1 到 3999 的范围内。
解题思路:switch运用
使用switch-case编写一个getValue函数,将阿拉伯数字与罗马字符对应起来。主函数中从第一个字符开始遍历,比较当前字符对应的数字与下一字符对应数字大小,大于等于则加,否则减,最后一个字符直接加。
class Solution {
public int romanToInt(String s) {
int result = 0,i=0,n =s.length();
while(i < n){
int current = getValue(s.charAt(i));
//比较当前字符与下一个字符,大于等于则加到result,小于则减。最后一个字符直接加
if(i==n-1 || current >= getValue(s.charAt(i+1))){
result += current;
}else{
result -= current;
}
i++;
}
return result;
}
private static int getValue(char c){
switch(c){
case 'I':
return 1;
case 'V':
return 5;
case 'X':
return 10;
case 'L':
return 50;
case 'C':
return 100;
case 'D':
return 500;
case 'M':
return 1000;
default:
throw new IllegalArgumentException("不合法的参数异常");
}
}
}
题目链接: 点击跳转至本题
题目大意:编写一个函数查找字符串数组中的最长公共前缀。
如果不存在公共前缀,返回空字符串 “”。
解题思路:横向扫描
取第一个字符串,与后面的每一个但字符串进行比较,使用indexOf(String s)函数,如果字符串包含第一个字符串时返回0,否则将第一个字符串末尾去掉,继续比较,直到字符串包含了第一个字符串为止。遍历结束后,第一个字符串已经变成了最长的公共前缀。双层while循环,外层控制遍历,内层负责比较。
class Solution {
public String longestCommonPrefix(String[] strs) {
//特判:如果字符串数组为空或长度为0,返回空字符串
if(strs == null || strs.length == 0){
return "";
}
//取第一个字符串
String res = strs[0];
int i = 1;
//遍历字符串数组
while(i < strs.length){
while(strs[i].indexOf(res) != 0){
//删除res的最后一个字符
res = res.substring(0,res.length()-1);
}
i++;
}
return res;
}
}
题目链接: 点击跳转至本题
题目大意:给定一个字符串,要求找出其中不含有重复字符的 最长子串 的长度。
解题思路:滑动窗口
HashMap是键不可以重复,值可以重复的集合。我们创建map集合,用键存储字符,用值存储对应的下标(人为规定为从1开始)。
在遍历字符串时,定义start作为滑动窗口的起始点,end作为滑动窗口的结束点。则每个滑动窗口的长度为end-start+1。实际情况是滑动窗口是不停的改变,当集合中没有出现过某个元素时,就将其加入集合,并且更新依次滑动窗口的长度;当集合中出现过某个元素时,就将滑动窗口的左边收缩,此时也会做添加和更新操作,但由于更新是和旧值的比较,此时并不会更新。
class Solution {
public int lengthOfLongestSubstring(String s) {
int n = s.length();
int ans = 0;
Map<Character,Integer> map = new HashMap<>();
//start作为滑动窗口的起始,end作为结尾
int start = 0;
for(int end = 0;end < n;end++){
char c = s.charAt(end);
if(map.containsKey(c)){
//如果集合中出现过,滑动窗口的左边就向右收缩
start = Math.max(map.get(c),start);
}
//如果集合中没有出现过,就将其加入集合,并计算滑动窗口的长度
map.put(c,end+1);
ans = Math.max(ans,end-start+1);
}
return ans;
}
}
题目链接: 点击跳转至本题
题目大意:给定一个字符串 s,找到 s 中最长的回文子串。可以假设 s 的最大长度为 1000。
解题思路:中心扩展
考虑从回文子串的中心开始向两边展开搜索匹配。我们需要遍历2n - 1
个中心,这是因为当回文的中心为双数时,有n-1种划分;当回文的中心为单数时,有 n 种划分。
class Solution {
public String longestPalindrome(String s) {
if(s == null || s.length() < 1){
return "";
}
//start和end分别作为扩展中心的左右边界
int start = 0,end = 0;
for(int i = 0;i < s.length();i++){
//有一个扩展中心时
int len1 = CenterExtension(s,i,i);
//有两个扩展中心时
int len2 = CenterExtension(s,i,i+1);
//len表示扩展中心的大小
int len = Math.max(len1,len2);
//如果扩展中心的大小>前一个扩展中心的大小,就更新start和end
if(len > end-start+1){
//start表示扩展中心左边界
start = i -(len-1)/2;
//end表示扩展中心右边界
end = i + len/2;
}
}
//substring[a,b)是左闭右开区间
return s.substring(start,end+1);
}
//中心扩展函数
private int CenterExtension(String s,int left,int right){
int L = left,R = right;
while(L>=0 && R < s.length() && s.charAt(L) == s.charAt(R)){
L--;
R++;
}
//满足条件时就开始向左向右进位,相当于最后的边界多了左右两个值,因此不是R-L+1
return R-L-1;
}
}
题目链接: 点击跳转至本题
题目大意:给定一个字符串,根据给定的行数,以从上往下、从左到右进行 Z 字形排列。要求输出需要从左往右逐行读取,产生出一个新的字符串。
解题思路:按行排序+标志变量
定义rows字符串,并将rows分隔成n份(n为行数numRows)。接着,遍历字符串 s 时把每个字符填到正确的行 rows[i]中 。遍历时标志变量在-1和1之间变换,从而控制了是向上遍历还是向下遍历。最终将n份结果合并到res返回。
class Solution {
public String convert(String s, int numRows) {
//特判:行数<2时直接返回原字符串
if(numRows < 2){
return s;
}
//定义字符串rows
List<StringBuilder> rows = new ArrayList<StringBuilder>();
//有多少行,就将rows分成多少份
for(int i = 0;i < numRows;i++){
rows.add(new StringBuilder());
}
int i = 0,flag = -1;
for(char c :s.toCharArray()){
rows.get(i).append(c);
//到达转折点时,执行反向
if(i==0 || i==numRows-1){
flag = -flag;
}
//向上或向下遍历
i += flag;
}
//定义res,将多份的rows合并起来作为结果
StringBuilder res = new StringBuilder();
for(StringBuilder row:rows){
res.append(row);
}
return res.toString();
}
}
题目链接: 点击跳转至本题
题目大意:实现一个 atoi 函数,使其能将字符串转换成整数。该函数会根据需要丢弃无用的开头空格字符,直到寻找到第一个非空格的字符为止。接下来的转化规则如下:
解题思路:
注意考虑三点:①去掉前导空格 ②处理正负号 ③注意越界情况。实际上工作中建议直接调用写好的API,自定义轮子,此题比较无聊。
class Solution {
public int myAtoi(String str) {
//将字符串转化为字符串数组
char[] chars = str.toCharArray();
int n = chars.length;
int i = 0;
//去掉前导空格
while(i < n && chars[i] == ' '){
i++;
}
//去掉前导空格后到达末尾了
if(i == n){
return 0;
}
boolean flag = true;
if(chars[i] == '-'){
//遇到负号
flag = false;
i++;
}else if(chars[i] == '+'){
//遇到正号
i++;
}else if(!Character.isDigit(chars[i])){
//其他符号
return 0;
}
int ans = 0;
while(i < n && Character.isDigit(chars[i])){
int digit = chars[i] - '0';
//应该是ans*10 +digit >Integer.MAX_VALUE,但*10和+digit可能越界,故移到右边
if(ans >(Integer.MAX_VALUE - digit)/10){
//越界处理
return flag ? Integer.MAX_VALUE:Integer.MIN_VALUE;
}
ans = ans * 10 + digit;
i++;
}
return flag ? ans : -ans;
}
}
题目链接: 点击跳转至本题
题目大意:给定一个整数,将其转为罗马数字。输入确保在 1 到 3999 的范围内。
解题思路:贪心算法
使用可变字符串StringBuilder存储答案,将阿拉伯数字和罗马数字分别用数组装起来。遍历数字数组,每一个数字与num比较,如果小于等于num就将对应下标的字符串数组中的值添加到sb中。并将num的值对应减去相应的数字。
class Solution {
int[] digit ={1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1};
String[] Rome = {"M","CM","D","CD","C","XC","L","XL","X","IX","V","IV","I"};
public String intToRoman(int num) {
//StringBuilder是可变字符
StringBuilder sb = new StringBuilder();
for(int i = 0;i<digit.length;i++){
while(digit[i] <= num){
num -= digit[i];
sb.append(Rome[i]);
}
}
return sb.toString();
}
}