数制转换问题
解决数制转换问题时,如果所给的数值不是用二进制表示的,一般用一个字符型数组来存放。数组中的每个元素分别存储它的一位数字。然后按位转换求和,得到十进制表示;再把十进制表示转换成所求的数制表示,转换的结果也用一个字符型数组来表示,每个元素表示转换结果的一位数字。
根据数制表示中相邻位的技术关系,可以把不同的数制分成两类。
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、我爱我.
- 如何判断回文串
解法一 :时间复杂度: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;
}
在某些回文问题里面,这个方法有着自己的独到之处,可以方便的解决一类问题。
解法三:
利用栈,将字符串全部压入栈,然后依次将各字符出栈,这样得到的就是原字符串的逆置串,分别和原字符串各个字符比较,就可以判断了。
- 最长回文子串
给定一个字符串,求它的最长回文子串的长度。
解法一:
最容易想到的办法是枚举所有的子串,分别判断其是否为回文。
// 枚举子串
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;
}
全排列&&全组合
- 全排列
输入一个字符串,打印出该字符串中字符的所有排列。
例如输入字符串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;
}
- 全组合
参考:
《编程之法:面试和算法心得》