一、偽26進制轉換
一個 char 類型的數組 chs,其中所有的字符都不同。
例如,chs=['A', 'B', 'C', ... 'Z'],
則字符串與整數的對應關系如下:
A, B... Z, AA,AB...AZ,BA,BB...ZZ,AAA... ZZZ, AAAA...
1, 2...26,27, 28... 52,53,54...702,703...18278, 18279...
例如,chs=['A', 'B', 'C'],則字符串與整數的對應關系如下: A,B,C,AA,AB...CC,AAA...CCC,AAAA... 1, 2,3,4,5...12,13...39,40...
給定一個數組 chs,實現根據對應關系完成字符串與整數相互轉換的兩個函數
/**
* @Author: 郜宇博
* @Date: 2021/12/9 15:06
* 一個 char 類型的數組 chs,其中所有的字符都不同。
* 例如,chs=['A', 'B', 'C', ... 'Z'],
* 則字符串與整數的對應關系如下:
* A, B... Z, AA,AB...AZ,BA,BB...ZZ,AAA... ZZZ, AAAA...
* 1, 2...26,27, 28... 52,53,54...702,703...18278, 18279...
* 實現根據對應關系完成字符串與整數相互轉換的兩個函數。
*/
public class CharToNum {
//number->char
public static String numberToChar(char[] charsMap,int number){
//1.獲取轉后的字符串長度
int strLength = 0;
int curPowNumber = 1;
int base = charsMap.length;
while (number >= curPowNumber){
number -= curPowNumber;
curPowNumber *= base;
strLength++;
}
//2.獲取各位上的字符
char[] resultChars = new char[strLength];
int index = 0;
int nCur = 0;
do {
curPowNumber /= base;
nCur = number / curPowNumber;
number %= curPowNumber;
//計算出的當前位置的個數 加上 之前的1個
resultChars[index++] = getKthString(charsMap,nCur+1);
}while (index != strLength);
return String.valueOf(resultChars);
}
public static char getKthString(char[] charsMap, int i) {
if (i == 0 || i > charsMap.length){
return 0;
}
return charsMap[i-1];
}
//char->number
public static int getNum(char[] chs, String str) {
if (chs == null || chs.length == 0) {
return 0;
}
char[] strc = str.toCharArray();
int base = chs.length;
int cur = 1;
int res = 0;
for (int i = strc.length - 1; i != -1; i--) {
res += getNthFromChar(chs, strc[i]) * cur;
cur *= base;
}
return res;
}
public static int getNthFromChar(char[] chs, char ch) {
return (ch-'A')+1;
}
public static void main(String[] args) {
char[] chs = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K',
'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
'X', 'Y', 'Z' };
System.out.println(numberToChar(chs, 18278));
System.out.println(getNum(chs, "AB"));
}
}
二、Snake最大長度
/**
* @Author: 郜宇博
* @Date: 2021/12/9 16:13
* 給定一個二維數組matrix,每個單元都是一個整數,有正有負。
* 最開始的時候小Q操縱 一條長度為0的蛇蛇從矩陣最左側任選一個單元格進入地圖,
* 蛇每次只能夠到達當前位置的右上相鄰,右側相鄰和右下相鄰的單元格。
* 蛇蛇到達一個單元格后,自身的長度會 瞬間加上該單元格的數值,任何情況下長度為負則游戲結束。
* 小Q是個天才,他擁有一 個超能力,可以在游戲開始的時候把地圖中的某一個節點的值變為其相反數
* (注:最多只能改變一個節點)。
* 問在小Q游戲過程中,他的蛇蛇最長長度可以到多少?
*/
public class SnakeMaxLength {
public static void main(String[] args) {
int[][] matrix = { { 1, -4, 10 }, { 3, -2, -1 }, { 2, -1, 0 }, { 0, 5, -2 } };
System.out.println(getMacLengthWithCatch(matrix));
}
/**
* 遞歸返回結果,兩個。
* 1.目前位置使用能力的獲得的長度
* 2.不使用能力獲取的長度
*/
public static class Info{
public int withAbilityLength;
public int withoutAbilityLength;
public Info(int withAbilityLength, int withoutAbilityLength) {
this.withAbilityLength = withAbilityLength;
this.withoutAbilityLength = withoutAbilityLength;
}
}
public static int getMaxLength(int[][] matrix){
int result = Integer.MIN_VALUE;
for (int i = 0 ; i < matrix.length;i++){
for (int j = 0; j < matrix[0].length;j++){
Info info = getLength(matrix, i, j);
result = Math.max(result,Math.max(info.withAbilityLength, info.withoutAbilityLength)) ;
}
}
return result;
}
public static Info getLength(int[][] matrix,int row,int col){
//base case->剛進去矩陣
if (col == 0){
return new Info(-(matrix[row][col]),matrix[row][col]);
}
//之前是否使用過能力到達的最大長度
int preUseAbilityMaxLength = -1;
int preNoAbilityMaxLength = -1;
//此時有之前最多有三種情況可以到達當前位置 左,左上,左下
//不在第一行
//1.左上
if (row >0){
Info leftUpInfo = getLength(matrix, row - 1, col - 1);
preNoAbilityMaxLength = leftUpInfo.withoutAbilityLength>=0?leftUpInfo.withoutAbilityLength:-1;
preUseAbilityMaxLength = leftUpInfo.withAbilityLength>=0?leftUpInfo.withAbilityLength:-1;
}
//2左
Info leftInfo = getLength(matrix,row,col-1);
preNoAbilityMaxLength = Math.max(leftInfo.withoutAbilityLength,preNoAbilityMaxLength);
preUseAbilityMaxLength = Math.max(leftInfo.withAbilityLength,preUseAbilityMaxLength);
//3.左下
if (row < matrix.length-1){
Info leftDownInfo = getLength(matrix,row+1,col-1);
preNoAbilityMaxLength = Math.max(leftDownInfo.withoutAbilityLength,preNoAbilityMaxLength);
preUseAbilityMaxLength = Math.max(leftDownInfo.withAbilityLength,preUseAbilityMaxLength);
}
//封裝自己的Info
int curUseMaxLength = -1;
int curNoMaxLength = -1;
//之前沒用,現在可以用可以不用
if (preNoAbilityMaxLength > 0){
curNoMaxLength = preNoAbilityMaxLength + matrix[row][col];
curUseMaxLength = preNoAbilityMaxLength - matrix[row][col];
}
//現在只能不用
if (preUseAbilityMaxLength > 0){
//更新用過的長度
curUseMaxLength = Math.max(curUseMaxLength,preUseAbilityMaxLength + matrix[row][col]);
}
return new Info(curUseMaxLength,curNoMaxLength);
}
/**
* 加入緩存機制
*/
public static int getMacLengthWithCatch(int[][]matrix){
int result = Integer.MIN_VALUE;
Info[][] dp = new Info[matrix.length][matrix[0].length];
for (int i = 0 ; i < matrix.length;i++){
for (int j = 0; j < matrix[0].length;j++){
Info info = getLengthWithCatch(matrix, i, j,dp);
result = Math.max(result,Math.max(info.withAbilityLength, info.withoutAbilityLength)) ;
}
}
return result;
}
public static Info getLengthWithCatch(int[][] matrix,int row,int col,Info[][]dp){
if (dp[row][col] != null){
return dp[row][col];
}
//base case->剛進去矩陣
if (col == 0){
dp[row][col] = new Info(-(matrix[row][col]),matrix[row][col]);
return dp[row][col];
}
//之前是否使用過能力到達的最大長度
int preUseAbilityMaxLength = -1;
int preNoAbilityMaxLength = -1;
//此時有之前最多有三種情況可以到達當前位置 左,左上,左下
//不在第一行
//1.左上
if (row >0){
Info leftUpInfo = getLengthWithCatch(matrix, row - 1, col - 1,dp);
preNoAbilityMaxLength = leftUpInfo.withoutAbilityLength>=0?leftUpInfo.withoutAbilityLength:-1;
preUseAbilityMaxLength = leftUpInfo.withAbilityLength>=0?leftUpInfo.withAbilityLength:-1;
}
//2左
Info leftInfo = getLengthWithCatch(matrix,row,col-1,dp);
preNoAbilityMaxLength = Math.max(leftInfo.withoutAbilityLength,preNoAbilityMaxLength);
preUseAbilityMaxLength = Math.max(leftInfo.withAbilityLength,preUseAbilityMaxLength);
//3.左下
if (row < matrix.length-1){
Info leftDownInfo = getLengthWithCatch(matrix,row+1,col-1,dp);
preNoAbilityMaxLength = Math.max(leftDownInfo.withoutAbilityLength,preNoAbilityMaxLength);
preUseAbilityMaxLength = Math.max(leftDownInfo.withAbilityLength,preUseAbilityMaxLength);
}
//封裝自己的Info
int curUseMaxLength = -1;
int curNoMaxLength = -1;
//之前沒用,現在可以用可以不用
if (preNoAbilityMaxLength > 0){
curNoMaxLength = preNoAbilityMaxLength + matrix[row][col];
curUseMaxLength = preNoAbilityMaxLength - matrix[row][col];
}
//現在只能不用
if (preUseAbilityMaxLength > 0){
//更新用過的長度
curUseMaxLength = Math.max(curUseMaxLength,preUseAbilityMaxLength + matrix[row][col]);
}
dp[row][col] =new Info(curUseMaxLength,curNoMaxLength);
return dp[row][col];
}
}
三、表達式計算
/**
* @Author: 郜宇博
* @Date: 2021/12/9 19:45
* 給定一個字符串str,str表示一個公式,公式里可能有整數、加減乘除符號和左右 括號,返回公式的計算結果。
* str="48*((70-65)-43)+8*1",返回-1816。
*/
public class Computer {
public static void main(String[] args) {
String expression = "48*((70-615)-43)+8*1";
System.out.println(getComputeResult(expression));
}
/**
* 遞歸,利用系統壓棧特性存儲 括號 內結果
* @param expression
* @return
*/
public static int getComputeResult(String expression){
char[] chars = expression.toCharArray();
int[] partResult = getPartResult(chars, 0);
return partResult[0];
}
//返回兩個結果,【0】為計算結果,【1】為到達的位置,上一層遞歸從下一個位置開始
public static int[] getPartResult(char[] chars,int cur){
LinkedList<String> queue = new LinkedList<String>();
int num = 0;
while (cur < chars.length && chars[cur] != ')'){
//是數字
if (chars[cur] >= '0' && chars[cur] <= '9'){
num = num * 10 + (chars[cur++] - '0');
}else if (chars[cur] != '('){
//運算符
compute(queue,num);
//壓入運算符
queue.addLast(String.valueOf(chars[cur++]));
num = 0;
}else {
//左括號
int[] partResult = getPartResult(chars, cur + 1);
num = partResult[0];
cur = partResult[1]+1;
}
}
compute(queue,num);
return new int[]{getQueueResult(queue),cur};
}
private static int getQueueResult(LinkedList<String> queue){
int result = 0;
boolean add = true;
int num = 0;
while (! queue.isEmpty()){
String cur = queue.pollFirst();
if ("+".equals(cur)){
add = true;
}else if ("-".equals(cur)){
add = false;
}else {
num = Integer.parseInt(cur);
result += add? num:(-num);
}
}
return result;
}
private static void compute(LinkedList<String> queue, int num) {
if (! queue.isEmpty()){
String top = queue.pollLast();
//如果是+,-就壓入
if ("+".equals(top) || "-".equals(top)){
queue.addLast(top);
}else {
//乘除,就
int cur = Integer.parseInt(queue.pollLast());
num = "*".equals(top)? (num*cur):(cur/num);
}
}
queue.addLast(String.valueOf(num));
}
}
四、最長公共子串(空間壓縮)
請注意區分子串和子序列的不同,給定兩個字符串str1和str2,求兩個字符串的最長公共子串。
動態規划空間壓縮
/**
* @Author: 郜宇博
* @Date: 2021/12/9 21:09
* 請注意區分子串和子序列的不同,給定兩個字符串str1和str2,求兩個字符串的最長公共子串。
* 動態規划空間壓縮的技巧講解
*/
public class LongestPublicChildArray {
public static void main(String[] args) {
String s1 = "ABC1234567MEFG";
String s2 = "HILL1234567MNOP";
System.out.println(getLength(s1, s2));
System.out.println(getLengthBySpaceCompress(s1, s2));
}
public static int getLength(String s1, String s2) {
//dp[i][j],表示s1以i結尾和s2以j結尾,構成的最長子串
int[][] dp = new int[s1.length()][s2.length()];
for (int i = 0; i < s2.length(); i++) {
dp[0][i] = s1.charAt(0) == s2.charAt(i) ? 1 : 0;
}
for (int i = 1; i < s1.length(); i++) {
for (int j = s2.length() - 1; j >= 0; j--) {
boolean b = s2.charAt(j) == s1.charAt(i);
if (j == 0) {
dp[i][0] = b ? 1 : 0;
} else {
dp[i][j] = dp[i - 1][j - 1] + (b ? 1 : 0);
}
}
}
return dp[s1.length() - 1][s2.length() - 1];
}
/**
* 每行元素只和左上角有依賴
* 從右上角開始,斜對角線,一直向左下走
*/
public static String getLengthBySpaceCompress(String s1, String s2) {
int row = 0;
int col = s2.length() - 1;
int max = 0;
int end = 0;
int length = 0;
char[] chs1 = s1.toCharArray();
char[] chs2 = s2.toCharArray();
while (row < chs1.length) {
int curRow = row;
int curCol = col;
length = 0;
while (curRow < s1.length() && curCol < s2.length()){
if (chs1[curRow] != chs2[curCol]){
length = 0;
}else {
length++;
}
//可更新,記錄end位置
if (length > max){
end = curRow;
max = length;
}
curRow++;
curCol++;
}
//起始點沒到最左邊,向左移動
if (col > 0){
col--;
}else {
//起始點在最左邊,向下移動
row++;
}
}
return s1.substring(end-max+1,end+1);
}
}