算法题--字符串

291 阅读6分钟

1.替换空格

    public String replaceSpace(StringBuffer str) {
        int count=0;
    	for(int i=0;i<str.length();i++){
            char c=str.charAt(i);
            if(c==' '){
                count++;
            }
        }
        int oldindex=str.length()-1;
        int newstrlen=count*2+str.length();
        str.setLength(newstrlen);
        int newindex=str.length()-1;
        for(;oldindex>=0&&newindex>=oldindex;oldindex--){
            char c1=str.charAt(oldindex);
            if(c1==' '){
                str.setCharAt(newindex--,'0');
                str.setCharAt(newindex--,'2');
                str.setCharAt(newindex--,'%');
            }else{
                str.setCharAt(newindex--,c1);
            }
        }
        return str.toString();
    }
}

2.字符串的排列

class Solution {
    LinkedList<String> res=new LinkedList();
    char[] track;
    public String[] permutation(String s) {
        track=s.toCharArray();
        backyard(0);
        return res.toArray(new String[res.size()]);
    }
    void backyard(int depth){
        if(depth==track.length){
            res.add(String.valueOf(track));
            return ;
        }
        Set set=new HashSet();
        for(int i=depth;i<track.length;i++){
            if(set.contains(track[i])){
                continue;
            }
            set.add(track[i]);
            swap(i,depth);
            backyard(depth+1);
            swap(depth,i);
        }
        
    }
    void swap(int a,int b){
        char tmp=track[a];
        track[a]=track[b];
        track[b]=tmp;
    }
}

3.左旋字符串

public class Solution {
    public String LeftRotateString(String str,int n) {
        //字符串重新拼接 主要是要懂得java的常用方法
        if(str==null||n>str.length()){
            return str;
        }
        return str.substring(n)+str.substring(0,n);
    }
}

4.翻转单词顺序列

public class Solution {
    public String ReverseSentence(String str) {
        //1.java StringBuffer的reverse方法
        //2.栈先进后出 感觉不好用还是1好用
        //3.滑动窗口 和1差不多
        //先全部反转
        StringBuffer str1=new StringBuffer(str);
        str1.reverse();
        StringBuffer result=new StringBuffer();
        int j=0,Blanknum=0;
        for(int i=0;i<str1.length();i++){
            if(str1.charAt(i)==' '&&i!=str1.length()-1){
                //局部反转回来
                StringBuffer str2= new StringBuffer(str1.substring(j,i));
                result.append(str2.reverse().toString()).append(" ");
                j=i+1;
                Blanknum++;
            }
            if(Blanknum!=0&&i==str1.length()-1){
                StringBuffer str3= new StringBuffer(str1.substring(j,i+1));
                result.append(str3.reverse().toString());
            }
        }
        if(Blanknum==0){
                return str;
            }
        return result.toString();
    }
}

5.正则表达式匹配



6.表示数值的字符串

sollution1:java

import java.util.regex.Pattern;
public class Solution {
    public boolean isNumeric(char[] str) {
        //要学会正则表达式的写法
        String pattern = "^[-+]?\\d*(?:\\.\\d*)?(?:[eE][+\\-]?\\d+)?$";
        String s = new String(str);
        return Pattern.matches(pattern,s);
    }
}

sollution2:C++

#include<bits/stdc++.h>
class Solution {
public:
    int StrToInt(string str) {
        if(str.size()==0)return 0;
        long long ans;
        stringstream ss;
       for(int i=0;i<str.size();i++){
           if(i==0){
               if((str[i]!='+'&&str[i]!='-')&&(str[i]-'0'>=9||str[i]-'0'<=0))
                   return 0;
           }
           if(i>0&&(str[i]-'0'>=9||str[i]-'0'<=0))return 0;
       }
        ss<<str;
        ss>>ans;
        if(ans>INT_MAX)return 0;
        return ans;
    }
};

7.字符流中第一个不重复的字符

import java.util.Queue;
import java.util.LinkedList;
import java.lang.Character;
 
public class Solution {
    //可以用hashmap或者数组在插入的时候判断有无重复
    //但因为这题不是一段字符串给完才判断,而是读一个返回一个值,所以每次用遍历的话,每次都是O(n)
    //所以这里应该用队列
    int[] charCnt = new int[128];
    Queue<Character> queue = new LinkedList<Character>();
    //Insert one char from stringstream
    public void Insert(char ch)
    {
        if (charCnt[ch]++ == 0) //新来的单身字符,入队
            queue.add(ch);
    }
  //return the first appearence once char in current stringstream
    public char FirstAppearingOnce()
    {
        Character CHAR = null;
        char c = 0;
        while ((CHAR = queue.peek()) != null) {
            c = CHAR.charValue();
            if (charCnt[c] == 1) //判断是否脱单了,没脱单则输出
                return c;
            else queue.remove(); //脱单了就移出队列,它不会再回来了
        }
        return '#'; //队空,返回#
    }
}

8.无重复字符的最长子串

用滑动窗口

class Solution {
public:
    int lengthOfLongestSubstring(string s) {
        if(s.length()==0)return 0;
        unordered_set<char> lookup;
        int left=0;
        int maxstr=0;

        for(int i=0;i<s.length();i++){
            while(lookup.find(s[i])!=lookup.end()){
                lookup.erase(s[left]);
                left++;
            }
            maxstr=max(maxstr,i-left+1);
            lookup.insert(s[i]);
        }
        return maxstr;
    }
};

9.长度最小的子数组

思路:滑动窗口

class Solution {
public:
    int minSubArrayLen(int s, vector<int>& nums) {
        int left=0;
        int minl=INT_MAX;//很大的值
        int tmpsum=0;
        for(int i=0;i<nums.size();i++){
             tmpsum+=nums[i];
            while(tmpsum>=s){
                minl=min(minl,i-left+1);
                tmpsum-=nums[left];
                left++;
            }
            
           
        }
        return (minl!=INT_MAX)?minl:0;
    }
};

10.Z字形变换

class Solution {
public:
    string convert(string s, int numRows) {
        if(numRows==1) return s;
        vector<string>stmp(min(int( s.size()),numRows));
        int curRow=0;
        bool flag=false;
        for(char c:s){
            stmp[curRow]+=c;
            if(curRow==0||curRow==numRows-1){
                flag=!flag;
            }
            curRow+=flag?1:-1;
        }
        string res;
        for(string row:stmp){
            res+=row;
        }
        return res;
    }
};

思路:按列来存,存完一列到一列,控制行号curRow。当遇到转折,也就是行号是0或者是最后一行时,用一个标记flag来转换 最后用一个string来存。

11.最长回文子串

思路:用动态规划

class Solution {
public:
    string longestPalindrome(string s) {
        int len=s.size();
        if(len==0||len==1)return s;
        int maxl=1;
        int start=0;
        vector<vector<int> >dp(len,vector<int>(len));
        for(int i=0;i<len;i++){
            dp[i][i]=1;
            if(s[i]==s[i+1]&&i<len-1){
                start=i;
                maxl=2;
                dp[i][i+1]=1;
            }
        }
        for(int l=3;l<=len;l++){
            for(int i=0;i+l-1<len;i++){
                int j=i+l-1;
                if(s[i]==s[j]&&dp[i+1][j-1]==1){
                    start=i;
                    maxl=l;
                    dp[i][j]=1;
                }
            }
        }
        return s.substr(start,maxl);
    }
};

用java实现

class Solution {
    public String longestPalindrome(String s) {
        int len=s.length();
        int maxl=1;
        int st=0;
        if(len==0||s==null)return "";
        int[][] dp=new int[len][len];
        for(int i=0;i<len;i++){
            dp[i][i]=1;
            if(i<len-1){
                if(s.charAt(i)==s.charAt(i+1)){
                dp[i][i+1]=1;
                maxl=2;
                st=i;
            }else{
                dp[i][i+1]=0;
            }
            }
        }
        for(int i=len-1;i>=0;i--){
            for(int j=i+1;j<len;j++){
                if(j-i==1)continue;
                if(s.charAt(i)==s.charAt(j)){
                    dp[i][j]=dp[i+1][j-1];
                    if(dp[i][j]==1&&maxl<(j-i+1)){
                        maxl=j-i+1;
                        st=i;
                    }
                }else{
                    dp[i][j]=0;
                }
            }
        }
        return s.substring(st,maxl+st);
    }
}

12.检查替换后的词是否有效

法1:

class Solution {
public:
    bool isValid(string S) {
        if(S.size()<=2)return false;
        if(S.size()%3!=0)return false;
        stack<char>st;
        for(char c:S){
            if(c!='c')
            st.push(c);
            else{
                if(st.empty())return false;
                char t1=st.top();
                st.pop();
                if(st.empty())return false;
                char t2=st.top();
                st.pop();
                if(t1!='b')return false;
                if(t2!='a')return false;
            }
        }
        if(!st.empty())
        return false;
        return true;
    }
};

根据题意,不难发现合法的字符串都是在abc的空隙中再插入abc,得出的新字符串中再插入abc。。。 所以用一个栈来存字符a和b,如果碰到c,就pop掉栈顶的两个字符看看c前面的第一个字符是不是b,第二的字符是不是a即可。

法二:

class Solution {
    public boolean isValid(String S) {
        while(S.contains("abc")){
            S=S.replaceAll("abc","");
        }
        return S.equals("");
    }
}

13.最长公共前缀

class Solution {
    public String longestCommonPrefix(String[] strs) {
        String prefix="";
        if(strs.length==0)return prefix;
        prefix=strs[0];
        for(int i=1;i<strs.length;i++){
            while(strs[i].indexOf(prefix)!=0){
                prefix=prefix.substring(0,prefix.length()-1);
                if(prefix.isEmpty())return "";
            }
            
        }
        return prefix;
    }
}

14.外观数列

先读懂题

找规律

发现每一个新状态都是从前一个状态得来 则用递归

class Solution {
    public String countAndSay(int n) {
        StringBuilder res=new StringBuilder();
        if(n==1)return "1";
        int cur=1;
        int pre=0;
        //递归
        String s=countAndSay(n-1);
        
        for(cur=1;cur<s.length();cur++){
        if(s.charAt(pre)!=s.charAt(cur)){
                int count=cur-pre;
                res.append(count).append(s.charAt(pre));
                pre=cur;
            }
        }
        if(pre!=cur){
            int count=cur-pre;
            res.append(count).append(s.charAt(pre));
        }
        return  res.toString();
    }
}

14.实现strStr()

模式匹配:KMP算法

15.回文子串

class Solution {
    public int countSubstrings(String s) {
        int length=s.length();
        if(s.equals("")||length==0)return 0;
        int[][]dp=new int[length][length];
        int sum=length;
        for(int i=0;i<length;i++)dp[i][i]=1;
        for(int i=length-1;i>=0;i--){
            for(int j=i+1;j<length;j++){
                if(s.charAt(i)==s.charAt(j)){
                    if(j-i==1){
                        dp[i][j]=1;
                        
                    }else{
                    dp[i][j]=dp[i+1][j-1];
                    
                    }
                }else{
                    dp[i][j]=0;
                }
                if(dp[i][j]==1)sum++;
            }
        }
        return sum;
    }
}

16.括号生成

class Solution {
    public List<String> generateParenthesis(int n) {
        List<String>res=new ArrayList();
        if(n==0)return res;

         dfs("",n,n,res);
         return res;
    }
     void dfs(String cur,int left,int right,List<String>res){
        if(left==0&&right==0){
            res.add(cur);
            return ;
        }
        if(left>right){
            return;
        }
        if(left>0){
            dfs(cur+"(",left-1,right,res);
        }
        if(right>0){
            dfs(cur+")",left,right-1,res);
        }
    }
}

思路:深度优先搜索

17.回文数

class Solution {
    public boolean isPalindrome(int x) {
        if(x<0)return false;
        int help=1;
        int tmp=x;
        while(tmp>=10){
            help*=10;
            tmp/=10;
        }
        //help/=10;
       // System.out.println(help)
        while(x!=0){
            if(x/help!=x%10){
                return false;
            }
            x=x%help/10;
            help/=100;
        }
        return true;
    }
}

18.反转字符串里的单词)(同4)

class Solution {
    public String reverseWords(String s) {
        String[] tmp=s.trim().split("\\s+");
        String res="";
        for(int i=tmp.length-1;i>0;i--){
            res+=tmp[i]+" ";
        }
        return res+tmp[0];
    }
}

知识点:

  • \s表示 空格,回车,换行等空白符,+号表示一个或多个的意思

  • split("\s+") 按空格,制表符等进行拆分

  • split(" +") 按空格进行拆分(也就是说只有按空格键流出来的空白才会是拆分的一句),这里用这个也可以