在LeetCode初级算法的字符串专题中,共给出了九道题目,分别为:反转字符串,整数反转,字符串中的第一个唯一字符,有效的字母异位词,验证回文字符串,字符串转换整数,实现strStr(),报数,最长公共前缀。涉及到字符串的常规应用和一些算法技巧,依次记录如下。


反转字符串(344)

  题目描述:编写一个函数,其作用是将输入的字符串反转过来。输入字符串以字符数组 char[] 的形式给出。不要给另外的数组分配额外的空间,你必须原地修改输入数组、使用 O(1) 的额外空间解决这一问题。可以假设数组中的所有字符都是 ASCII 码表中的可打印字符。

  例如:输入:["h","e","l","l","o"]      输出:["o","l","l","e","h"]

  解析:

  若给出的是字符数组,则可以直接通过简单的首尾交换完成反转;若给出的是一个字符串,有三种方法:(1)将String变为StringBuffer,借助StringBuffer类的reverse()方法直接完成反转;(2)通过String的toCharArray()方法变为字符数组,首尾交换;(3)借助栈的先进后出实现。

    //方法一:首尾交换,输入为字符数组
public void reverseString(char[] s) {
int len = s.length; //数组长度
for(int i=0;i<len/2;i++){ //遍历一半长度,首尾交换
char temp=s[i];
s[i]=s[len-i-1];
s[len-i-1]=temp;
}
}
//方法二:StringBuffer的reverse方法,输入为String
public String reverseString(String s) {
StringBuffer result = new StringBuffer(s);
result = result.reverse(); //调用reverse方法
return result.toString();
}

整数反转(7)

  题目描述:给出一个 32 位的有符号整数,你需要将这个整数中每位上的数字进行反转,反转后如果整数溢出则返回0。

  例如: 输入: 123 输出: 321   输入: -123 输出: -321

  解析:

  类似于反转字符串,整数反转也有两种方法,(1)将整数转为字符串,通过字符串的反转来实现整数的反转,整数转字符串String.valueOf(num),字符串转整数Integer.parseInt(str);(2)弹出和压入数字,通过pop = x % 10;取出末尾数字,压入到结果的前面。显然,方法二较好。

  这里需要注意的还有整数溢出的处理,同样有两种方法,一种可以通过java的异常机制,捕获对应的整数溢出异常,进行处理(NumberFormatException),还有一种是进行提前进行数字是否溢出的检查。

    //方法一,转为字符串实现
public int reverse(int x) {
String s=String.valueOf(x);
if(x<0)
s=s.substring(1);
StringBuffer strBuf = new StringBuffer(s);
String str=strBuf.reverse().toString();
try{
return x>0 ? Integer.parseInt(str) : -1*Integer.parseInt(str);
}catch(NumberFormatException e){
return 0;
}
} //方法二,弹出和推入数字 & 溢出前进行检查
public int reverse(int x) {
int rev = 0;
while (x != 0) {
int pop = x % 10; //弹出末尾数字
x /= 10;
if (rev > Integer.MAX_VALUE/10 || (rev == Integer.MAX_VALUE / 10 && pop > 7)) return 0;
if (rev < Integer.MIN_VALUE/10 || (rev == Integer.MIN_VALUE / 10 && pop < -8)) return 0;
rev = rev * 10 + pop; //推入
}
return rev;
}

字符串中的第一个唯一字符(387)

  题目描述:给定一个字符串,找到它的第一个不重复的字符,并返回它的索引。如果不存在,则返回 -1。

  例如:s = "leetcode" 返回 0.    s = "loveleetcode",返回 2.

  解析:

  方法一:用哈希表建立每个字符和其出现次数的映射,然后按顺序遍历字符串,找到第一个出现次数为1的字符,返回其位置即可。方法二:使用模式匹配从前(indexOf)和从后(lastIndexOf)匹配每一个字符,相等即为唯一。

    //方法一:哈希表
public int firstUniqChar(String s) {
Map<Character,Integer> map = new HashMap<Character,Integer>();
for(int i=0;i<s.length();i++){
char c=s.charAt(i);
map.put(c,map.getOrDefault(c,0)+1);
}
for(int i=0;i<s.length();i++)
if(map.get(s.charAt(i))==1)
return i;
return -1;
} //方法二:模式匹配
public int firstUniqChar(String s) {
for(int i=0;i<s.length();i++){
char c=s.charAt(i);
if(s.indexOf(c)==s.lastIndexOf(c))
return i;
}
return -1;
}

有效的字母异位词(242)

  题目描述:给定两个字符串 s 和 t ,编写一个函数来判断 t 是否是 s 的一个字母异位词。

  例如:输入: s = "anagram", t = "nagaram"   输出: true

  解析:

  方法一:用哈希表建立每个字符和其出现次数的映射,然后判断两个字符串建立的哈希表是否相同;方法二,将字符串转为字符数组,对字符数组排序,比较排序之后的数组是否相同。方法三:哈希表的变化,如果只有小写字母,可以用数组代替哈希表,一个字符串+,一个字符串-,若是字母异位词,所有值都为0.

    //方法一:哈希表
public boolean isAnagram(String s, String t) {
if(s.length()!=t.length())
return false;
Map<Character,Integer> s_map=new HashMap<Character,Integer>();
Map<Character,Integer> t_map=new HashMap<Character,Integer>();
for(int i=0;i<s.length();i++){
char si=s.charAt(i),ti=t.charAt(i);
s_map.put(si,s_map.getOrDefault(si,0)+1);
t_map.put(ti,t_map.getOrDefault(ti,0)+1);
}
if(s_map.entrySet().equals(t_map.entrySet()))
return true;
return false;
}
//方法二:字符数组排序
public boolean isAnagram(String s, String t) {
if (s.length() != t.length()) {
return false;
}
char[] str1 = s.toCharArray();
char[] str2 = t.toCharArray();
Arrays.sort(str1);
Arrays.sort(str2);
return Arrays.equals(str1, str2);
}
//方法三:哈希表的变化,如果只有小写字母,可以用数组代替哈希表
public boolean isAnagram(String s, String t) {
if (s.length() != t.length())
return false;
int[] counter = new int[26];
for (int i = 0; i < s.length(); i++) {
counter[s.charAt(i) - 'a']++;
counter[t.charAt(i) - 'a']--;
}
for (int count : counter) {
if (count != 0)
return false;
}
return true;
}

实现strStr() (28)

  题目描述:给定一个 haystack 字符串和一个 needle 字符串,在 haystack 字符串中找出 needle 字符串出现的第一个位置 (从0开始)。如果不存在,则返回-1。

  例如:输入: haystack = "hello", needle = "ll"    输出: 2

  本题与C语言的 strstr() 以及 Java的 indexOf() 定义相符。具体可以参见另一篇博客"串的模式匹配算法"。

验证回文串 (125)

  题目描述:给定一个字符串,验证它是否是回文串,只考虑字母和数字字符,可以忽略字母的大小写。将空字符串定义为有效的回文串。

  例如:输入: "A man, a plan, a canal: Panama"    输出: true

  解析:

  方法一:暴力解决,去掉字符串中的特殊字符,将所有字母变为小写(toLowerCase),然后首尾比较。方法二:对撞指针(类似于快排的思想),两端扫描,特殊字符跳过

    //方法一:暴力解决
public boolean isPalindrome(String s) {
s=s.toLowerCase(); //全部变为小写
char[] strArray = s.toCharArray(); //变为字符数组
String str = "";
for(char c:strArray)
if((c>='a'&&c<='z')||(c>='0'&&c<='9'))
str += c;
int len=str.length();
for(int i=0;i<len/2;i++)
if(str.charAt(i)!=str.charAt(len-1-i))
return false;
return true;
}
//方法二:对撞指针
public boolean isPalindrome(String s) {
s=s.toLowerCase(); //全部变为小写
int len=s.length();
for(int i=0,j=len-1;i<j;){
char si=s.charAt(i),sj=s.charAt(j);
if(!((si>='a'&&si<='z')||(si>='0'&&si<='9')))
i++;
else if(!((sj>='a'&&sj<='z')||(sj>='0'&&sj<='9')))
j--;
else if(si!=sj)
return false;
else{
i++;
j--;
}
}
return true;
}

字符串转换整数atoi(8)

  题目描述:请你来实现一个 atoi 函数,使其能将字符串转换成整数。首先,该函数会根据需要丢弃无用的开头空格字符,直到寻找到第一个非空格的字符为止。当我们寻找到的第一个非空字符为正或者负号时,则将该符号与之后面尽可能多的连续数字组合起来,作为该整数的正负号;假如第一个非空字符是数字,则直接将其与之后连续的数字字符组合起来,形成整数。该字符串除了有效的整数部分之后也可能会存在多余的字符,这些字符可以被忽略,它们对于函数不应该造成影响。

  例如:输入: "4193 with words" 输出: 4193

  解析:题目比较简单,依次处理字符串开头为数字,为"+",为"-",或者为其他字符的情况。

    public int myAtoi(String str) {
str = str.trim(); //去掉两边的空格
if(str.length()==0)
return 0;
char first = str.charAt(0);
String res="";
if(first>='0'&&first<='9') //首字母为数字
res += first;
else if(first=='-'||first=='+'){ //首字母为正负号,需要判断后续字符是否为数字
if(str.length()==1)
return 0;
char second = str.charAt(1);
if(second>='0'&&second<='9')
res +=first;
}
if(res!=""){ //存在数字
for(int i=1;i<str.length();i++){
char c=str.charAt(i);
if(c>='0'&&c<='9')
res += c;
else
break;
}
}
else return 0; try{
return Integer.parseInt(res);
}catch(NumberFormatException e){
if(res.charAt(0)=='-')
return Integer.MIN_VALUE;
else
return Integer.MAX_VALUE;
}
}

报数(38)

  报数序列是一个整数序列,按照其中的整数的顺序进行报数,得到下一个数。其前五项如下,给定一个正整数 n(1 ≤ n ≤ 30),输出报数序列的第 n 项。

  1. 1

  2. 11

  3. 21

  4. 1211

  5. 111221

  解析:当前n的报数结果是基于n-1的报数结果,基于n-1的结果对字符串进行分析即可,相当于按序统计n-1结果的字符种类及数目。

    public String countAndSay(int n) {
String[] res = new String[n+1];
res[1]="1";
for(int i=2;i<n+1;i++){
int count=1;
res[i]="";
char pre = res[i-1].charAt(0); //前一个字符
for(int j=1;j<res[i-1].length();j++){
char c=res[i-1].charAt(j);
if(c==pre) //相等计数加一
count++;
else{ //不相等写入结果,count重新置为1
res[i] += String.valueOf(count)+pre;
count = 1;
pre = c;
}
}
res[i] += String.valueOf(count)+pre;
}
System.out.println(res[n]);
return res[n];
}

最长公共前缀 (14)

  编写一个函数来查找字符串数组中的最长公共前缀。如果不存在公共前缀,返回空字符串 ""。所有输入只包含小写字母 a-z 。

  例如:输入: ["flower","flow","flight"] 输出: "fl"

  解析:此题有多种方法可解,方法一:水平扫描法,前i个字符串的公共前缀与第i+1个字符串的公共前缀就是前i+1个字符串的公共前缀;方法二:垂直扫描法,将每个字符串的第i个字符(i从0开始)依次比较;方法三:分治法,用分治的思想将原问题分解为两个子问题。

    //方法一:水平扫描
public String longestCommonPrefix(String[] strs) {
if(strs.length==0)
return "";
//最长公共前缀长度不会超过其中的任意一个
String prefix = strs[0]; //假设第一个字符串就是最长公共前缀,通过比较逐渐缩短
int j;
for(int i=1;i<strs.length;i++){
int len=strs[i].length()<prefix.length() ? strs[i].length() : prefix.length();
for(j=0;j<len;j++){ //与strs[i]比较,最长可能为len
if(prefix.charAt(j)!=strs[i].charAt(j))
break; //不等,停止,最长为j
}
if(j==0)
return "";
prefix = prefix.substring(0,j); }
return prefix;
}
//方法三:分治法
public String longestCommonPrefix(String[] strs) {
if (strs == null || strs.length == 0) return "";
return longestCommonPrefix(strs, 0 , strs.length - 1);
} private String longestCommonPrefix(String[] strs, int l, int r) {
if (l == r)
return strs[l];
else {
int mid = (l + r)/2;
String lcpLeft = longestCommonPrefix(strs, l , mid);
String lcpRight = longestCommonPrefix(strs, mid + 1,r);
return commonPrefix(lcpLeft, lcpRight);
}
} String commonPrefix(String left,String right) {
int min = Math.min(left.length(), right.length());
for (int i = 0; i < min; i++)
if ( left.charAt(i) != right.charAt(i) )
return left.substring(0, i);
return left.substring(0, min);
}

总结

  本博客记录了LeetCode初级算法中的字符串模块给出的9道典型题目,重点是字符串的相关操作以及主要的算法技巧的应用,如对撞指针,哈希表,分治思想等等。

【LeetCode算法】LeetCode初级算法——字符串的更多相关文章

  1. LeetCode初级算法的Python实现--字符串

    LeetCode初级算法的Python实现--字符串 # 反转字符串 def reverseString(s): return s[::-1] # 颠倒数字 def reverse(x): if x ...

  2. LeetCode初级算法--字符串01:反转字符串

    LeetCode初级算法--字符串01:反转字符串 搜索微信公众号:'AI-ming3526'或者'计算机视觉这件小事' 获取更多算法.机器学习干货 csdn:https://blog.csdn.ne ...

  3. LeetCode初级算法--字符串02:字符串中的第一个唯一字符

    LeetCode初级算法--字符串02:字符串中的第一个唯一字符 搜索微信公众号:'AI-ming3526'或者'计算机视觉这件小事' 获取更多算法.机器学习干货 csdn:https://blog. ...

  4. LeetCode初级算法的Python实现--链表

    LeetCode初级算法的Python实现--链表 之前没有接触过Python编写的链表,所以这里记录一下思路.这里前面的代码是和leetcode中的一样,因为做题需要调用,所以下面会给出. 首先定义 ...

  5. LeetCode初级算法--其他02:有效的括号

    LeetCode初级算法--其他02:有效的括号 搜索微信公众号:'AI-ming3526'或者'计算机视觉这件小事' 获取更多算法.机器学习干货 csdn:https://blog.csdn.net ...

  6. LeetCode初级算法之数组:48 旋转图像

    旋转图像 题目地址:https://leetcode-cn.com/problems/rotate-image/ 给定一个 n × n 的二维矩阵表示一个图像. 将图像顺时针旋转 90 度. 说明: ...

  7. LeetCode初级算法的Python实现--排序和搜索、设计问题、数学及其他

    LeetCode初级算法的Python实现--排序和搜索.设计问题.数学及其他 1.排序和搜索 class Solution(object): # 合并两个有序数组 def merge(self, n ...

  8. LeetCode初级算法的Python实现--数组

    LeetCode初级算法的Python实现--数组 # -*- coding: utf-8 -*- """ @Created on 2018/6/3 17:06 @aut ...

  9. LeetCode初级算法(数组)解答

    这里记录了LeetCode初级算法中数组的一些题目: 加一 本来想先转成整数,加1后再转回去:耽美想到测试的例子考虑到了这个方法的笨重,所以int类型超了最大范围65536,导致程序出错. class ...

随机推荐

  1. MySQL:浅析 Impossible WHERE noticed after reading const tables

    使用 EXPLAIN 执行计划的时候,在 Extra 中偶尔会看到这样的描述: Impossible WHERE noticed after reading const tables 字面上的意思是: ...

  2. [bzoj2242][Sdoi2011]计算器_exgcd_BSGS

    计算器 bzoj-2242 Sdoi-2011 题目大意:裸题,支持快速幂.扩展gcd.拔山盖世 注释:所有数据保证int,10组数据. 想法:裸题,就是注意一下exgcd别敲错... ... 最后, ...

  3. CSDN日报20170416 ——《为什么程序猿话少钱多死得早?》

    [程序人生]为什么程序猿话少钱多死得早? 作者:文奇 我在想,程序猿都是话少吗?不一定吧.像我和我的同学.都是话非常多啊. 可是经历过非常多事的如今.再想想,发现事实的确如此.程序猿确实话少. 我是一 ...

  4. Android Studio怎样删除module

    当你想在Android Studio中删除某个module时,大家习惯性的做法都是选中要删除的module.右键去找delete.可是 在Android Studio中你选中module,右键会发现没 ...

  5. Python学习笔记13:标准库之子进程(subprocess包)

    ubprocess包主要功能是运行外部的命令和程序.从这个意义上来说,subprocess的功能与shell类似. subprocess以及经常使用的封装函数 当我们执行python的时候,我们都是在 ...

  6. QQ好友列表数据模型封装

    QQ好友中的信息较多.假设我们单独从plist 中直接取出数据 是能够解决这个问题 可是相当复杂.以为列表中分组 .每组中还有不同信息 大致模型是 数组套数组  数组套字典 所以我们要封装数据模型 / ...

  7. CentOS安装、配置APR和tomcat-native

    APR:Apache Portable Run-time libraries,Apache可移植执行库 在早期的Apache版本号中.应用程序本身必须可以处理各种详细操作系统平台的细节,并针对不同的平 ...

  8. getElementById和querySelector区别

    1.常见的获取元素的方法有3种,分别是通过元素ID document.getElementById('idName');.通过标签名字document.getElementsByTagName(tag ...

  9. iOS开发中UIDatePicker控件的使用方法简介

    iOS上的选择时间日期的控件是这样的,左边是时间和日期混合,右边是单纯的日期模式. 您可以选择自己需要的模式,Time, Date,Date and Time  , Count Down Timer四 ...

  10. java异常处理和自定义异常利用try和catch让程序继续下去(回来自己再写个例子试运行下)

    注意:想在catch的参数里使用自定义的异常,则必须先将这个异常抛出才行.(throws是具有抛出异常的能力,并未抛出,throw new MyException是抛出异常,catch是捕获异常,只有 ...