POJ刷题

数制转换问题


解决数制转换问题时,如果所给的数值不是用二进制表示的,一般用一个字符型数组来存放。数组中的每个元素分别存储它的一位数字。然后按位转换求和,得到十进制表示;再把十进制表示转换成所求的数制表示,转换的结果也用一个字符型数组来表示,每个元素表示转换结果的一位数字。

根据数制表示中相邻位的技术关系,可以把不同的数制分成两类。
1)一类数制表示中,相邻位的基数是等比关系,例如我们熟悉的十进制表示。
第 k 位的值 xk 表示 xk*(10^k) 11 = 1*10^1 + 1*10^0
2) 一类数制表示中,相邻位的基数是不等比的,例如skew数。
第 k 位的值 xk 表示 xk*(2^(k+1)-1) 11(skew) = 1*(2^(1+1)-1) + 1*(2^(0+1)-1) = 4

十进制转为其他进制需要分两种情况考虑:
1)数制B中的相邻基数位是等比的,就是把十进制转换成二进制的短除的方法。
2)数制B中的相邻基数位是不等比,需要先判断dndn-1dn-2...d1(十进制)在数制B中需要的位数m,然后从高位到低位依次计算bmbm-1bm-2...b1。


通过计算数组的 index 来选择目标值,而不是逐一匹配。
(数组读取0(1))

    private static void format(char[] datas) {
        char plain[] = {'V','W','X','Y','Z','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U'};
        for (int i = 0; i < datas.length; i++) {
            if (datas[i] >= 'A' && datas[i] <= 'Z') {
                datas[i] = plain[datas[i] - 'A'];
            }
        }
    }

字符串问题


** 回文串**

回文,英文palindrome,指一个顺着读和反过来读都一样的字符串,比如madam、我爱我.

  1. 如何判断回文串
    解法一 : 时间复杂度:O(n),空间复杂度:O(1)
    同时从字符串头尾开始向中间扫描字串,如果所有字符都一样,那么这个字串就是一个回文。
    采用这种方法的话,我们只需要维护头部和尾部两个扫描指针即可。
    // 检查是否是回文串
    static boolean IsPalindrome(String string, int n) {
        // 非法输入
        if (string == null || n == 0) {
            return false;
        }

        int front = 0;
        int back = n - 1;
        while (front < back) {
            if (string.charAt(front) != string.charAt(back)) {
                return false;
            }
            front++;
            back--;
        }
        return true;
    }

解法二:时间复杂度:O(n),空间复杂度:O(1)
上述解法一从两头向中间扫描,那么是否还有其它办法呢?我们可以先从中间开始、然后向两边扩展查看字符是否相等。

    // 检查是否是回文串
    static boolean IsPalindrome(String string, int n) {
        // 非法输入
        if (string == null || n == 0) {
            return false;
        }

        int left, right;
        // 奇数长度
        if (n % 2 != 0) {
            left = n / 2 - 1;
            right = n / 2 + 1;
        } else {
            left = n / 2;
            right = n / 2 + 1;
        }
        while (left >= 0 && right <= n - 1) {
            if (string.charAt(left) != string.charAt(right)) {
                return false;
            }
            left--;
            right++;
        }
        return true;
    }

在某些回文问题里面,这个方法有着自己的独到之处,可以方便的解决一类问题。

解法三:
利用栈,将字符串全部压入栈,然后依次将各字符出栈,这样得到的就是原字符串的逆置串,分别和原字符串各个字符比较,就可以判断了。

  1. 最长回文子串

给定一个字符串,求它的最长回文子串的长度。

解法一:
最容易想到的办法是枚举所有的子串,分别判断其是否为回文。

    // 枚举子串
    static int LongestPalindrome(String string, int n) {
        int subLength = n;
        String temp;

        while (subLength > 0) {
            for (int i = 0; i <= n - subLength; i++) {
                temp = string.substring(i, subLength + i);
                if (IsPalindrome(temp, temp.length())) {
                    return subLength;
                }
            }
            subLength--;
        }
        return 0;
    }

缺点:这个思路初看起来是正确的,但却做了很多无用功,如果一个长的子串包含另一个短一些的子串,那么对子串的回文判断其实是不需要的。

解法二:
如果一段字符串是回文,那么以某个字符为中心的前缀和后缀都是相同的,例如以一段回文串“aba”为例,以b为中心,它的前缀和后缀都是相同的,都是a。
那么,我们可以可以枚举中心位置,然后再在该位置上用扩展法,记录并更新得到的最长的回文长度呢。

    // 枚举中心点
    static int LongestPalindrome(String string, int n) {
        if (string == null || n == 0) {
            return -1;
        }

        int max = 0;
        int l, r, c;

        for (int i = 0; i < n; i++) {
            // 回文串为奇数时
            l = i - 1;
            r = i + 1;
            c = 1;
            while (l >= 0 && r <= n - 1) {
                if (string.charAt(l) == string.charAt(r)) {
                    c = c + 2;
                    l--;
                    r++;
                } else {
                    break;
                }
            }
            if (c > max) {
                max = c;
            }

            // 回文串为偶数时
            l = i;
            r = i + 1;
            c = 0;
            while (l >= 0 && r <= n - 1) {
                if (string.charAt(l) == string.charAt(r)) {
                    c = c + 2;
                    l--;
                    r++;
                } else {
                    break;
                }
            }
            if (c > max) {
                max = c;
            }
        }

        return max;
    }

全排列&&全组合


  1. 全排列

输入一个字符串,打印出该字符串中字符的所有排列。
例如输入字符串abc,则输出由字符a、b、c 所能排列出来的所有字符串abc、acb、bac、bca、cab 和 cba。

解法一:递归实现
从集合中依次选出每一个元素,作为排列的第一个元素,然后对剩余的元素进行全排列,如此递归处理,从而得到所有元素的全排列。以对字符串abc进行全排列为例,我们可以这么做:以abc为例
固定a,求后面bc的排列:abc,acb,求好后,a和b交换,得到bac
固定b,求后面ac的排列:bac,bca,求好后,c放到第一位置,得到cba
固定c,求后面ba的排列:cba,cab。

   // 字符串的全排列
   static void AllRange(char[] string, int from, int to) {
       if (from > to) {
           return;
       }
       if (from == to) {
           for (int i = 0; i <= to; i++) {
               System.out.print(string[i]);
           }
           System.out.println();
       } else {
           for (int i = from; i <= to; i++) {
               swap(string, from, i);
               AllRange(string, from+1, to);  //递归调用
               swap(string, from, i);
           }
       }
   }

   static void swap(char[] string, int from, int to) {
       char temp = string[from];
       string[from] = string[to];
       string[to] = temp;
   }

解法二:去重的全排列

    // 字符串的全排列
    static void AllRange(char[] string, int from, int to) {
        if (from > to) {
            return;
        }
        if (from == to) {
            for (int i = 0; i <= to; i++) {
                System.out.print(string[i]);
            }
            System.out.println();
        } else {
            for (int i = from; i <= to; i++) {
                if (IsSwap(string, from, i)) {
                    Swap(string, from, i);
                    AllRange(string, from + 1, to); // 递归调用
                    Swap(string, from, i);
                }
            }
        }
    }

    // 在 str 数组中,[start,end) 中是否有与 str[end] 元素相同的
    private static boolean IsSwap(char[] str, int start, int end) {
        for (int i = start; i < end; i++) {
            if (str[i] == str[end])
                return false;
        }
        return true;
    }

    static void Swap(char[] string, int from, int to) {
        char temp = string[from];
        string[from] = string[to];
        string[to] = temp;
    }
  1. 全组合

参考:
《编程之法:面试和算法心得》

你可能感兴趣的:(POJ刷题)