字符串问题经典问题

一。字符串循环移位问题;

 给定一个字符串S[0...N-1],要求把S的前k个字符移动到S的尾部,如把字符串“abcdef”向左移动2位得到“cdefab”。

  • 循环左移n+k位和k位的结果是一样的;
  • 循环右移k位相当于循环左移n-k位。
  • 算法要求:时间复杂度O(n), 空间复杂度O(1).
    • 不能采用BF,时间复杂度为O(kN);
    • 这里采用类似矩阵逆置的思想:(XTYTT=  YX.
    •     /**
           * 该算法实现将字符串循环左移k位
           * @param s
           * @param k
           * @return
           */
          public static String leftShifting(String s, int k) {
              char[] ch = s.toCharArray();
              k %= s.length();
              
              leftShiftingHelper(ch, 0, k-1);
              leftShiftingHelper(ch, k, ch.length-1);
              leftShiftingHelper(ch, 0, ch.length-1);
              
              return new String(ch, 0, ch.length);
          }
          
          
          /**
           * 将字符数组的m-n位逆置
           * @param ch
           * @param m
           * @param n
           */
          private static char[] leftShiftingHelper(char[] ch, int m, int n) {
              int i = m, j = n;
              while(i < j) {
                  char c = ch[i];
                  ch[i++] = ch[j];
                  ch[j--] = c;
              }
              return ch;
          }
      View Code 

 

二。压缩空格问题。将给定字符串中所有的空格去掉;

 给定某字符串S,该字符串中有若干空格,删除这些空格,并返回修改后的字符串,要求时间复杂度为:O(N),空间复杂度为O(1).

  • 给出两个指针,一个指针向后寻找不为空的元素,一个指针指示目前字符串已经达到的位数;代码如下:
  • /**
         * *算法描述:
         * 删除给定字符串中所有的空格
         * @param s
         * @return
         */
        public static String deleteSpaceSpaces(String s) {
            if(s == null || s.length() == 0) return s;
            int i = 0, j = 0;
            char[] ch = s.toCharArray();
            while(j < ch.length && i < ch.length) {
                if(ch[j] != ' ') {
                    if( i != j) {
                        ch[i] = ch[j];
                    }
                    i++;
                }
                j++;
            }
            return new String(ch, 0, i);
        }
    View Code

 

三。求一个数组中最大的2个数。(TopN问题)

 给定一个数组,求该数组中最大的两个数。可以假设数组的长度大于2. O(N) and O(1).

    /**
     * 该算法寻找一个数组中前2大的数,假设数组长度大于2
     * @param nums
     * @return
     */
    public static int[] topTwo(int[] nums) {
        int[] res = new int[2];
        res[0] = nums[0];
        res[1] = nums[0];
        for(int i=0; i) {
            if(nums[i] > res[0]) {
                res[1] = res[0];
                res[0] = nums[i];
            }
            else if(nums[i] > res[1]) 
                res[1] = nums[i];
        }
        return res;
    }
    
View Code

 

 

 

四。Huffman编码问题(字符串的最优无损压缩)

  • 凡是问如何保证传输中信息不丢失,最优编码,无损压缩等都要自动反应到Huffman编码!
  • 思想:根据源字符出现的(估算)概率对字符编码,概率高的字符使用较短的编码,概率低的字符使用较长的编码,从而使得编码后的字符串长度期望最小。
  • 是一种贪心算法:每次总选择两个最小概率的字符节点合并。(概率可用频率代替)
  • 初始节点为N的,形成Huffman树后一共有(2*N-1)个节点。
  • 使用数组代替二叉树;
  • Huffman编码不是唯一的。
  • import java.util.ArrayList;
    import java.util.Arrays;
    import java.util.HashMap;
    import java.util.Iterator;
    import java.util.Map;
    import java.util.Map.Entry;
    
    class Huffman {
        Huffman parent;
        Huffman left;
        Huffman right;
        int weight;
    }
    
    public class HuffmanCoding {
        
        public static ArrayList Huff(String s) {
            ArrayList list = new ArrayList();
            HashMap map = computWordFrequency(s);
            Huffman[] huffTree = new Huffman[2 * map.size() - 1]; //用数组模拟霍夫曼树
            for(int i=0; i)
                huffTree[i] = new Huffman();
            
            Iterator> it = map.entrySet().iterator();
            int i=0;
            while(it.hasNext()) {
                Map.Entry entry = (Entry) it.next();
                huffTree[i].weight = (int) entry.getValue();
                System.out.println(i + " " + huffTree[i].weight);
                i++;
            }
            //建树
            int len = map.size();
            for(int j=map.size(); j) {
                int[] mins = topTwoMin(huffTree, 0, len);
                System.out.println(Arrays.toString(mins));
                huffTree[j].weight = huffTree[mins[0]].weight + huffTree[mins[1]].weight;
                huffTree[j].left = huffTree[mins[0]];
                huffTree[j].right = huffTree[mins[1]];
                huffTree[mins[0]].parent = huffTree[j];
                huffTree[mins[1]].parent = huffTree[j];
                len++;
            }
            //编码
            for(int j=0; j) {
                Huffman temp = huffTree[j];
                StringBuffer sb = new StringBuffer();
                while(temp.parent != null) {
                    if(temp.parent.left == temp)
                        sb.append("0");
                    else
                        sb.append("1");
                    temp = temp.parent;
                }
                list.add(sb.toString());
            }
            
            return list;
        }
        
        /**
         * 该算法寻找一个数组中最小的2数,假设数组长度大于2
         * @param nums
         * @return
         */
        public static int[] topTwoMin(Huffman[] huffTree, int start, int end) {
            int[] res = new int[2];
            res[0] = Integer.MAX_VALUE;
            res[1] = Integer.MAX_VALUE;
            int[] index = new int[2];
            for(int i=start; i) {
                if(huffTree[i].parent == null && huffTree[i].weight < res[0]) {
                    res[1] = res[0];
                    res[0] = huffTree[i].weight;
                    index[1] = index[0];
                    index[0] = i;
                }
                else if(huffTree[i].parent == null && huffTree[i].weight < res[1]) {
                    res[1] = huffTree[i].weight;
                    index[1] = i;
                }
            }
            return index;
        }
        
        /**
         * 该函数返回每个字符出现的词频数
         * @param s
         * @return
         */
        public static HashMap computWordFrequency(String s) {
            HashMap map = new HashMap();
            char[] ch = s.toCharArray();
            for(int i=0; i) {
                if(!map.containsKey(ch[i]))
                    map.put(ch[i], 1);
                else 
                    map.put(ch[i], map.get(ch[i]) + 1);
            }
            return map;
        }
        
        public static void main(String[] args) {
            // TODO Auto-generated method stub
            String s = "aadabcbacdaebdebcdbebdacaedaacaebcaaaaa";
            System.out.println(Huff(s));
        }
    
    }
    View Code

     

五。字符串的全排列枚举

  • (无重复字符串的递归是最优算法)分析:如给出字符串“1234”,
    • 若以1当首位,则需要再对“234”进行全排列;
    • 若依2当首位,则需要再对“134”进行全排列;
    • 若以3为首位,则需要再对“214”进行全排列;
    • 若以4为首位,则需要再对“231”进行全排列;
    •     /**
           * 当给定数组中没有重复元素时,将数组中饿元素全排序
           * @param nums
           * @param k
           */
          public static void permutation(int[] nums, int k) {
              if(k == nums.length-1) {
                  for(int n : nums)
                      System.out.print(n + " ");
                  System.out.println();
                  return;
              }
              for(int i=k; i) {
                  int temp = nums[i];
                  nums[i] = nums[k];
                  nums[k] = temp;
                  
                  permutation(nums, k+1);
                  
                  temp = nums[i];
                  nums[i] = nums[k];
                  nums[k] = temp;
              }
              
          }
      View Code

       

  • 空间换时间
  • (非递归实现)从字典顺序12345到字典逆序54321
    • 因此问题演变为:找一个序列的下一个序列是多少?
    • 逐位考虑哪个能增大?
      • 一个数右面有比它大的数存在,它就能增大;
    • 这个数应该增大到多少?
      • 增大到它后面比它大的所有数中最小的那个。
      • 如“21543”的下一个序列应该是“23xxx”。显然xxx应该有小到大排列:145,故“21543”的写一个序列应该是“23145”。
      • 从后往前找,找最后一个升序的位置;
      • 找后面比该位置大的所有数中最小的一个;
      • 交换这两个位置;
      • 翻转后面的位数。
  • 如何知道一个给定的序列,知道它是全排列中的第几个排列?
    • Cantor数组。

 

 

六。KMP算法

  • 字符串查找问题:给定文本串text和模式串pattern,从文本串text中找出模式串pattern第一次出现的位置。
  • 暴力求解(Brute Force)?O(M*N) O(1)
  • KMP算法是一种线性时间复杂度的字符串匹配算法,是对BF的一种改进。O(M*N) O(M)

 

转载于:https://www.cnblogs.com/little-YTMM/p/5421079.html

你可能感兴趣的:(字符串问题经典问题)