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

 给定一个字符串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).

对于难输入的字符串用特殊短字符串代替Python 字符串难题_字符串

对于难输入的字符串用特殊短字符串代替Python 字符串难题_字符串_02

/**
     * 该算法寻找一个数组中前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)