很久没做题了,堕落了。
给自己订个计划,尽量每天做一题力扣或者一道剑指offer的题目。
题目描述:
代码:
public class Design {
/**
* 全排列递归法
* @param n
*/
public static void print1ToMaxOfNDigits(int n) {
if (n <= 0) {
return;
}
char[] number = new char[n];
for (int i = 0; i < 10; i++) {
number[0] = (char) (i + '0');
allRankDigitDance(number, 1);
}
}
public static void allRankDigitDance(char[] number, int len) {
if (len == number.length) {
printNumber(number);
return;
}
for (int i = 0; i < 10; i++) {
number[len] = (char) (i + '0');
allRankDigitDance(number, len + 1);
}
}
public static void printNumber(char[] number) {
int len = number.length;
boolean notZeroStartFlag = false;
for (int i = 0; i < len; i++) {
if ((number[i] != '0' && !notZeroStartFlag) || (!notZeroStartFlag && i == len - 1)) {
notZeroStartFlag = true;
}
if (notZeroStartFlag) {
System.out.print(number[i]);
}
}
System.out.print(" ");
}
/**
* 大数加法
* @param n
*/
public static void print1ToMaxOfNDigitsByAdd(int n) {
if (n <= 0) {
return;
}
char[] number = new char[n];
for (int i = 0; i < n; i++) {
number[i] = '0';
}
printNumber(number);
while (!increment(number)) {
printNumber(number);
}
}
public static boolean increment(char[] number) {
// 这里需要判断是否溢出了,只有999999..99 加1才会溢出
boolean isOverFlow = false;
// 进位
boolean carryBit = false;
int num = number[number.length - 1] - '0' + 1;
if (num < 10) {
number[number.length - 1] = (char) (num + '0');
} else {
carryBit = true;
number[number.length - 1] = (char) (num - 10 + '0');
int i = number.length - 2;
for (; i >= 0; i--) {
num = number[i] - '0' + (carryBit ? 1 : 0);
if (num < 10) {
number[i] = (char) (num + '0');
carryBit = false;
break;
} else {
carryBit = true;
number[i] = (char) (num - 10 + '0');
}
}
if (i == -1 && carryBit) {
isOverFlow = true;
}
}
return isOverFlow;
}
public static void main(String[] args) {
print1ToMaxOfNDigitsByAdd(2);
}
}
看到大数加法的printNumber这个方法的时间复杂度是o(n),我想了一下,好像无论怎么变,它始终都是o(n)的时间复杂度啊,各位有好的想法吗,O(1)?
然后,扩展练习:
在前面的代码中,我们用一个char类型的字符表示十进制数字的一位。
8bit的char型字符最多能表示256个字符,而十进制数字只有0~9的10个
数字。因此,用char型字符来表示十进制数字没有充分利用内存,有一
些浪费。
是滴。是挺浪费的。
最直白的想法就是用4位来表示一个数字。
那么能不能还用char,但是一个char类型的字符表示两个数字呢。
比如:
char c = " 0 0 1 0 1 1 0 1"
高四位代表一个数字,低四位代表一个数字,在实际操作的时候,如果想获取高四位,那就让 c & " 1 1 1 1 0 0 0 0",然后再移位,就能获取高四位了,这样好像有一点影响效率了。
另外呢:
延伸题目是大数运算:(有一个数为负数的时候,相当于大数减法,需要注意一下有个判断两个数大小的方法)
代码如下:
public class DesignNew {
public static void bigNumCompute(String first, String second) {
if (first == null || first.length() == 0 || second == null || second.length() == 0) {
return;
}
if ((first.charAt(0) == '-' && second.charAt(0) == '-')
|| (first.charAt(0) != '-' && second.charAt(0) != '-')) {
// 当做加法来做
boolean addOrNot = false;
if (first.charAt(0) == '-') {
addOrNot = true;
}
if (first.charAt(0) == '+' || first.charAt(0) == '-') {
first = first.substring(1, first.length());
}
if (second.charAt(0) == '+' || second.charAt(0) == '-') {
second = second.substring(1, second.length());
}
int len1 = first.length();
int len2 = second.length();
char[] res = new char[len1 > len2 ? len1 + 1 : len2 + 1];
boolean carryBit = false;
int len = res.length;
char[] firstC = new StringBuilder(first).reverse().toString().toCharArray();
char[] secondC = new StringBuilder(second).reverse().toString().toCharArray();
int num1 = 0, num2 = 0, num = 0;
for (int i = 0; i < len; i++) {
num1 = 0;
num2 = 0;
num = 0;
if (i < len1) {
num1 = firstC[i] - '0';
}
if (i < len2) {
num2 = secondC[i] - '0';
}
num = num1 + num2 + (carryBit ? 1 : 0);
if (num > 9) {
res[i] = (char) (num - 10 + '0');
carryBit = true;
} else {
res[i] = (char) (num + '0');
}
}
String resC = new String(res);
if (addOrNot) {
System.out.print("-");
}
Design.printNumber(new StringBuilder(resC).reverse().toString().toCharArray());
} else {
// 当做减法来做
boolean firstNegtive = true;
if (second.charAt(0) == '-') {
firstNegtive = false;
}
if (first.charAt(0) == '+' || first.charAt(0) == '-') {
first = first.substring(1, first.length());
}
if (second.charAt(0) == '+' || second.charAt(0) == '-') {
second = second.substring(1, second.length());
}
boolean maxFlag = judgeMax(first, second);
boolean resFlag = !(firstNegtive && maxFlag);
if (!maxFlag) {
String tempStr = first;
first = second;
second = tempStr;
}
boolean negtiveCarryBit = false;
char[] res = new char[first.length()];
char[] firstC = new StringBuilder(first).reverse().toString().toCharArray();
char[] secondC = new StringBuilder(second).reverse().toString().toCharArray();
int num1 = 0, num2 = 0;
for (int i = 0; i < res.length; i++) {
num1 = 0;
num2 = 0;
if (i < firstC.length) {
num1 = firstC[i] - '0';
}
if (i < secondC.length) {
num2 = secondC[i] - '0';
}
num1 = num1 - (negtiveCarryBit ? 1 : 0);
negtiveCarryBit = false;
if (num1 < num2) {
negtiveCarryBit = true;
num1 += 10;
}
res[i] = (char) (num1 - num2 + '0');
}
res = new StringBuilder(new String(res)).reverse().toString().toCharArray();
if (!resFlag) {
System.out.print("-");
}
Design.printNumber(res);
}
}
public static boolean judgeMax(String first, String second) {
// 最基本的先比较两个数的位数吧
if (first.length() > second.length()) {
return true;
} else if (first.length() < second.length()) {
return false;
} else {
// 相等的情况
// 从高位往低位比就可以了
// 如:
// 987654321
// 986543210
// 从9开始比,发现从左数第三位, 7>6 那自然就是第一个数大了
int index = 0;
while (index < first.length() && first.charAt(index) == second.charAt(index)) {
index++;
}
if (index == first.length()) {
return true;
} else {
if (first.charAt(index) > second.charAt(index)) {
return true;
} else if (first.charAt(index) < second.charAt(index)) {
return false;
} else {
return true;
}
}
}
}
public static void main(String[] args) {
bigNumCompute("9999999999999999999991", "10000000000000000000000");
}
}