字符串类编程汇总

除了数组和链表数据结构,字符串也是编程工作面试中的另一热点话题。我参加过的编码面试基本都问过关于字符串的问题。

如果你了解数组,那么你就能轻易地解决基于字符串的问题,因为字符串就是字符数组。因此,你通过解决数组编程问题学到的所有技巧,也能用来解决字符串编程问题。

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);
		 }
	 }
  1. 如何检查一个字符串是否仅包含数字?
    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;
	}

猜你喜欢

转载自blog.csdn.net/sky_noodle/article/details/82934559