• 字符串问题经典问题


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

     给定一个字符串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<nums.length; 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<String> Huff(String s) {
              ArrayList<String> list = new ArrayList<String>();
              HashMap<Character, Integer> map = computWordFrequency(s);
              Huffman[] huffTree = new Huffman[2 * map.size() - 1]; //用数组模拟霍夫曼树
              for(int i=0; i<huffTree.length; i++)
                  huffTree[i] = new Huffman();
              
              Iterator<Entry<Character, Integer>> 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<huffTree.length; 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<map.size(); 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<end; 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<Character, Integer> computWordFrequency(String s) {
              HashMap<Character, Integer> map = new HashMap<Character, Integer>();
              char[] ch = s.toCharArray();
              for(int i=0; i<ch.length; 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<nums.length; 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)
  • 相关阅读:
    SSH 连接超时解决办法
    alter system switch logfile和alter system archive log current 的区别
    Oracle 删除归档日志脚本
    Oracle 11g 新特性简介
    Oracle sqlplus 常用命令总结
    Oracle 11g 新特性简介
    计算文件的MD5值上传到服务器 下载验证文件是否被篡改
    看不下去的代码放这有机会用手机看。。。
    C++ Primer第一章学习笔记——C++初邂逅
    OpenCV学习笔记(四十七)——VideoWriter生成视频流highgui
  • 原文地址:https://www.cnblogs.com/little-YTMM/p/5421079.html
Copyright © 2020-2023  润新知