除了数组和链表数据结构,字符串也是编程工作面试中的另一热点话题。我参加过的编码面试基本都问过关于字符串的问题。
如果你了解数组,那么你就能轻易地解决基于字符串的问题,因为字符串就是字符数组。因此,你通过解决数组编程问题学到的所有技巧,也能用来解决字符串编程问题。
1.查找字符串中第一个非重复的字符?
使用LinkedHashMap和两个for循环实现。
LinkedHashMap保存了字符串的顺序,遍历第一遍字符串,key,value,key为字符,value为字符个数。
public static void findNoDup(String s) {
Map<Character,Integer> counts = new LinkedHashMap<>(s.length());
for(char c:s.toCharArray()) {
counts.put(c, counts.containsKey(c) ? counts.get(c)+1:1);
}
for(Entry<Character,Integer> entry:counts.entrySet()) {
if(entry.getValue()==1)
System.out.println(entry.getKey());
//return entry.getKey();
}
}
利用set和list
set存放重复,list存放非重复
public static void findNoDup(String s) {
Set<Character> repeat = new HashSet<>();
List<Character> noRepeat = new ArrayList<>();
for (int i = 0; i < s.length(); i++) {
char c = s.charAt(i);
if (repeat.contains(c))
continue;
if (noRepeat.contains(c)) {
noRepeat.remove((Character) c);
repeat.add(c);
} else {
noRepeat.add(c);
}
}
System.out.println(noRepeat.get(0));
}
2.判断两个字符串是否为变形词
例如"abc" 和"cba"
由于"aabc"和"aacb"情况,所以不能用set。
利用map数组,存放256AscII。字符串a存在的字符计数,遍历字符串b。
也可用hashmap替代map数组。
public static boolean isDeformation(String s,String b) {
if(s.length()!=b.length())
return false;
char[] cs=s.toCharArray();
char[] cb=b.toCharArray();
int[] map=new int[256];
for(int i=0;i<cs.length;i++) {
map[cs[i]]++;
}
for(int j=0;j<cb.length;j++) {
if(map[cb[j]]==0)
return false;
map[cb[j]]--;
}
return true;
}
public static boolean isDeformation(String s, String b) {
if (s.length() != b.length())
return false;
char[] cs = s.toCharArray();
char[] cb = b.toCharArray();
Map<Character, Integer> map = new HashMap<>();
for (char c : cs) {
map.put(c, map.containsKey(c) ? map.get(c) + 1 : 1);
}
for (char c : cb) {
if (map.get(c) == 0)
return false;
map.put(c, map.get(c) - 1);
}
return true;
}
3.反转字符串
首尾指针反转
public static String reverse(String s) {
if(s==null||s.length()==0)return s;
char[] ch=s.toCharArray();
int left=0;
int right=ch.length-1;
while(left<right) {
char tmp=ch[left];
ch[left]=ch[right];
ch[right]=tmp;
left++;
right--;
}
return new String(ch);
}
栈
public static String reverse(String s) {
if(s==null||s.length()==0) return s;
Stack<Character> st = new Stack<>();
char [] ch = s.toCharArray();
for(char c:ch) {
st.push(c);
}
for(int i=0;i<ch.length;i++) {
ch[i]=st.pop();
}
return new String(ch);
}
递归
public static String reverse(String s){
if(s==null||s.length()==0) return s;
if(s.length()==1)
return s;
else {
return reverse(s.substring(1))+s.charAt(0);
}
}
- 如何检查一个字符串是否仅包含数字?
isDigit判断
public static boolean isNum(String s) {
char[] ch = s.toCharArray();
for(char c:ch) {
if(!Character.isDigit(c))
return false;
}
return true;
}
正则
public static boolean isNumeric(String str){
Pattern pattern = Pattern.compile("[0-9]*");
return pattern.matcher(str).matches();
}
ascII
public static boolean isNum(String s) {
char[] ch = s.toCharArray();
for (char c : ch) {
if (c < 48 || c > 57)
return false;
}
return true;
}
5.如何搜索一个字符串的所有排列情况?
6.在不使用任何库的情况下,如何反转给定句子中的单词?
例如:“hello world” => “olleh dlrow”
public static String reverseWords(String s) {
char [] ch =s.toCharArray();
int begin=0;
for(int i=0;i<ch.length;i++) {
if(ch[i]==' ') {
swap(ch,begin,i-1);
begin=i+1;
}
if(i==ch.length-1) {
swap(ch,begin,i);
}
}
return new String(ch);
}
public static char[] swap(char[] ch,int left,int right) {
while(right>left) {
char tmp = ch[left];
ch[left]=ch[right];
ch[right]=tmp;
left++;
right--;
}
return ch;
}
6.在不使用任何库的情况下,如何反转给定句子中的单词?
例如:“hello world” => “world hello”
反转两次
public static String reverseWords(String s) {
char [] ch = s.toCharArray();
swap(ch,0,ch.length-1);
int begin=0;
for(int i=0;i<ch.length;i++) {
if(ch[i]==' ') {
swap(ch,begin,i-1);
begin=i+1;
}
if(i==ch.length-1) {
swap(ch,begin,i);
}
}
return new String(ch);
}
public static char[] swap(char[] ch,int left,int right) {
while(right>left) {
char tmp = ch[left];
ch[left]=ch[right];
ch[right]=tmp;
left++;
right--;
}
return ch;
}
使用StringBuilder
public String ReverseSentence(String str) {
if(str.length()==0||str.trim().length()==0)
return str;
String [] strs=str.split(" ");
StringBuffer sb= new StringBuffer();
for(int i=strs.length-1;i>=0;i--){
sb.append(strs[i]);
if(i>0)
sb.append(" ");
}
return sb.toString();
}
7.判断字符串的旋转词
例如"abc" 的旋转词为"abc",“bca”,“cab”
构造新字符串"abc"+"abc"旋转词一定是其子串
public static boolean check(String a, String b) {
if(a.length()!=b.length())
return false;
String c= a+a;
if(c.indexOf(b)!=-1)
return true;
return false;
}
8.左旋转字符串
S=”abcXYZdef”,要求输出循环左移3位后的结果,即“XYZdefabc”
先旋转左移部分,再旋转不移动部分,再整体旋转
public String LeftRotateString(String str,int n) {
int len =str.length();
if(n<=0||n>len||len<=0)
return str;
char[] charStr=str.toCharArray();
reverse(charStr,0,n-1);
reverse(charStr,n,len-1);
reverse(charStr,0,len-1);
return String.valueOf(charStr);
}
public static void reverse(char[] charStr,int i,int j){
while(i<j){
char temp=charStr[i];
charStr[i]=charStr[j];
charStr[j]=temp;
i++;
j--;
}
}
9.验证是否为回文串
public boolean isPalindrome(String s) {
char [] ch =s.toCharArray();
int left=0;
int right=ch.length-1;
while(left<right) {
if(ch[left]!=ch[right]) {
return false;
}
left++;
right--;
}
return true;
}
10.最长回文串
<1>暴力求解
求出每一个子串,之后判断是不是回文,找到最长的那个。
求每一个子串时间复杂度O(N^2), 判断子串是不是回文O(N),两者是相乘关系,所以时间复杂度为O(N^3)。
public String longestPalindrome(String s) {
if(s==null||s.length()==0)
return s;
char [] ch = s.toCharArray();
int start =0;
int longest = 1;
for(int i=0;i<ch.length;i++) {
for(int j=i+1;j<ch.length;j++) {
int tmp1=i;
int tmp2=j;
while(tmp1<tmp2&&ch[tmp1]==ch[tmp2]) {
tmp1++;
tmp2--;
}
if(tmp1>=tmp2&&j-i+1>longest) {
longest=j-i+1;
start=i;
}
}
}
return s.substring(start, start+longest);
// return longest;
}
<2>中心展开
中心扩展就是把给定的字符串的每一个字母当做中心,向两边扩展,这样来找最长的子回文串。算法复杂度为O(N^2)。
需要考虑两种情况:
长度为奇数的回文串,比如a, aba, abcba
长度为偶数的回文串,比如aa, abba
可以将每个字符间插入间隔符’#'这样所有的字符串都变为基数
例如"aba"=>"#a#b#a#"
“abba”=>"#a#b#b#a"
public String longestPalindrome(String s) {
if(s==null||s.length()==0)
return s;
String n = ods(s);
char [] ch = n.toCharArray();
int longest=1;
int start =0;
for(int i=0;i<ch.length;i++) {
int left = i-1;
int right = i+1;
while(left>=0&&right<ch.length&&ch[left]==ch[right]) {
if(longest<right-left+1) {
longest=right-left+1;
start=left;
}
left--;
right++;
}
}
return drop(n.substring(start,start+longest));
}
public static String drop(String s) {
char [] ch = s.toCharArray();
String n = new String();
for(int i=0;i<ch.length;i++) {
if(ch[i]!='#')
n=n+ch[i];
}
return n;
}
public static String ods(String s) {
String n = new String ("#");
char [] ch = s.toCharArray();
for(char c:ch) {
n=n+c+'#';
}
return n;
}
string longestPalindrome(string &s)
{
const int len = s.size();
int maxlen = 1;
int start = 0;
for(int i = 0; i < len; i++)//求长度为奇数的回文串
{
int j = i - 1, k = i + 1;
while(j >= 0 && k < len && s.at(j) == s.at(k))
{
if(k - j + 1 > maxlen)
{
maxlen = k - j + 1;
start = j;
}
j--;
k++;
}
}
for(int i = 0; i < len; i++)//求长度为偶数的回文串
{
int j = i, k = i + 1;
while(j >= 0 && k < len && s.at(j) == s.at(k))
{
if(k - j + 1 > maxlen)
{
maxlen = k - j + 1;
start = j;
}
j--;
k++;
}
}
return s.substr(start, maxlen);
}
private static int maxLen = 0;
private static String sub = "";
public static String longestPalindrome(String s) {
if(s.length() <= 1)
return s;
for(int i = 0;i < s.length()-1;i++){
findLongestPalindrome(s,i,i);//单核回文
findLongestPalindrome(s,i,i+1);//双核回文
}
return sub;
}
public static void findLongestPalindrome(String s,int low,int high){
while (low >= 0 && high <= s.length()-1){
if(s.charAt(low) == s.charAt(high)){
if(high - low + 1 > maxLen){
maxLen = high - low + 1;
sub = s.substring(low , high+1);
}
low --;//向两边扩散找当前字符为中心的最大回文子串
high ++;
}
else
break;
}
}
字符串的全排列
给定一个没有重复数字的序列,返回其所有可能的全排列。
示例:
输入: [1,2,3]
输出:
[
[1,2,3],
[1,3,2],
[2,1,3],
[2,3,1],
[3,1,2],
[3,2,1]
]
public static List<List<Integer>> permute(int[] nums) {
List<List<Integer>> res = new ArrayList<List<Integer>>();
res = permuteDFS(nums, 0, res);
return res;
}
public static List<List<Integer>> permuteDFS(int[] nums, int start, List<List<Integer>> res) {
List<Integer> list = new ArrayList<Integer>();
if (start == nums.length - 1) {
for (int i : nums)
list.add(i);
res.add(list);
}
for (int i = start; i < nums.length; i++) {
swap(nums, i, start);
permuteDFS(nums, start = 1, res);
swap(nums, i, start);
}
return res;
}
public static void swap(int[] nums, int left, int right) {
int temp = nums[left];
nums[left] = nums[right];
nums[right] = temp;
}