一、斐波那契公式(矩陣方法、快速冪)
/**
* @Author: 郜宇博
* @Date: 2021/11/27 20:47
*/
public class Fibonacci {
public static void main(String[] args) {
System.out.println(getFibonacci1(20));
System.out.println(getFibonacci2(20));
}
public static int getFibonacci1(int N) {
if (N == 1) {
return 1;
}
if (N == 2) {
return 1;
}
return getFibonacci1(N - 1) + getFibonacci1(N - 2);
}
/**
* 斐波那契公式
* 使用線性代數方法進行計算
*/
public static int getFibonacci2(int N) {
if (N < 0) {
return -1;
}
if (N == 1 || N == 2) {
return 1;
}
//獲取fibonacci的base矩陣
int[][] base = {{1, 1}, {1, 0}};
//計算base的n-2次冪
int[][] res = matrixPower(base, N - 2);
return res[0][0] + res[1][0];
}
//矩陣次冪
public static int[][] matrixPower(int[][] base, int p) {
//單位矩陣
int[][] resMatrix = new int[base.length][base[0].length];
for (int i = 0; i < base.length; i++) {
resMatrix[i][i] = 1;
}
int[][] temp = base;
//快速冪
for (; p != 0; p >>= 1) {
if ((p & 1) != 0) {
resMatrix = muliMatrix(resMatrix, temp);
}
temp = muliMatrix(temp, temp);
}
return resMatrix;
}
//計算矩陣乘法
public static int[][] muliMatrix(int[][] temp, int[][] temp1) {
int [][] res = new int[temp.length][temp1[0].length];
for (int i = 0 ; i < temp.length; i++){
for (int j = 0 ; j < temp1[0].length; j++){
for (int k = 0; k < temp1.length; k++){
res[i][j] += temp[i][k] * temp1[k][j];
}
}
}
return res;
}
}
二、拼不出三角形
在迷迷糊糊的大草原上,小紅撿到了n根木棍,第i根木棍的長度為i, 小紅現在很開心。想選出其中的三根木棍組成美麗的三角形。 但是小明想捉弄小紅,想去掉一些木棍,使得小紅任意選三根木棍都不能組成 三角形。
請問小明最少去掉多少根木棍呢?
給定N,返回至少去掉多少根?
/**
* @Author: 郜宇博
* @Date: 2021/11/27 21:58
*/
public class DeleteWood {
//保證剩下的都是斐波那契數就拼不出三角形
public static int minDelete(int m) {
int fiboCount = getFiboCount(m);
return m-fiboCount;
}
/**
* 計算[1-N]數字內有多少個斐波那契數
*/
public static int getFiboCount(int N){
int index1 = 1;
int index2 = 2;
int res = 2;
while (index1 + index2 <= N){
index1 += index2;
index2 = index1 - index2;
res++;
}
return res;
}
public static void main(String[] args) {
int test = 8;
System.out.println(minDelete(test));
}
}
三、01揹包
牛牛準備參加學校組織的春遊, 出發前牛牛準備往揹包裡裝入一些零食, 牛牛的揹包容 量為w。 牛牛家裡一共有n袋零食, 第i袋零食體積為v[i]。 牛牛想知道在總體積不超過揹包容量的情況下,他一共有多少種零食放法(總體積為0也算一種放法)。
/**
* @Author: 郜宇博
* @Date: 2021/11/27 22:12
*/
public class Bag01Problem {
public static void main(String[] args) {
int[] arr = { 4, 3, 2,5,3,5,8,2,3,4,58};
int w = 8;
int[][] ints = new int[arr.length][9];
for (int i = 0 ; i < ints.length ; i++){
Arrays.fill(ints[i],-1);
}
System.out.println(func4(arr, w,0));
System.out.println(func5(arr, w));
}
public static int func4(int[] v,int weight,int index){
if (weight < 0){
return 0;
}
if (weight == 0){
return 1;
}
if (index == v.length-1){
return weight - v[index] >=0?2:1;
}
int s = func4(v,weight-v[index],index+1);
int u = func4(v,weight,index+1);
return s + u;
}
public static int func5(int[]v,int weight){
int[][] dp = new int[v.length][weight + 1];
for (int i = 0; i < v.length; i++){
dp[i][0] = 1;
}
for (int i = 0; i <= weight; i++){
dp[v.length-1][i] = i - v[v.length-1] >=0?2:1;
}
for (int i = v.length-2; i >=0; i--){
for (int j = 0; j <= weight; j++){
dp[i][j] = j-v[i] < 0?dp[i+1][j]:dp[i+1][j-v[i]]+dp[i+1][j];
}
}
return dp[0][weight];
}
}
四、列印目錄層級
給你一個字串型別的陣列arr,譬如: String[] arr = { "b\cst", "d\", "a\d\e", "a\b\c" }; 你把這些路徑中蘊含的目錄結構給畫出來,子目錄直接列在父目錄下面,並比父目錄 向右進兩格,就像這樣:
a
b
c
d
e
b
cst
d
同一級的需要按字母順序排列,不能亂。
/**
* @Author: 郜宇博
* @Date: 2021/11/28 22:17
* 給你一個字串型別的陣列arr,譬如: String[] arr = { "b\\cst", "d\\", "a\\d\\e", "a\\b\\c" };
* 你把這些路徑中蘊含的目錄結構給畫出來,子目錄直接列在父目錄下面,並比父目錄 向右進兩格
*/
public class PrintCatalogue {
public static void main(String[] args) {
String[] arr = { "b\\cst", "d\\", "a\\d\\e", "a\\b\\c" };
print(arr);
}
static class Node{
public String name;
//使用順序map,可以實現列印的時候按順序
public TreeMap<String ,Node> nextMap;
public Node(String name){
this.name = name;
nextMap = new TreeMap<>();
}
}
/**
* 字首樹方式
* 將每個字母對應一個node,如果要加入的在當前字母的next中,那麼放在next中,沒有就新建
*/
public static void print(String[] strings){
Node head = generateFolderTree(strings);
printTree(head,0);
}
private static Node getPrefixTree(String[] strings) {
Node head = new Node("");
Node cur = head;
for (String str: strings){
String[] letters = getLetters(str);
//更新cur回到head
cur = head;
for (String letter: letters){
if (!cur.nextMap.containsKey(letter)) {
cur.nextMap.put(letter,new Node(letter));
}
cur = cur.nextMap.get(letter);
}
}
return head;
}
public static Node generateFolderTree(String[] folderPaths) {
Node head = new Node("");
for (String foldPath : folderPaths) {
String[] paths = foldPath.split("\\\\");
Node cur = head;
for (int i = 0; i < paths.length; i++) {
if (!cur.nextMap.containsKey(paths[i])) {
cur.nextMap.put(paths[i], new Node(paths[i]));
}
cur = cur.nextMap.get(paths[i]);
}
}
return head;
}
public static void printTree(Node head, int level) {
if (level != 0){
System.out.println(getSpace(level)+head.name);
}
for (Node node: head.nextMap.values()){
printTree(node,level+1);
}
}
//按照樹的層數獲取不同數量的空格1層沒有,2層2個
public static String getSpace(int level){
StringBuilder stringBuilder = new StringBuilder();
for (int i = 1; i < level;i++){
stringBuilder.append(" ");
}
return stringBuilder.toString();
}
//將 "a\\b\\c" => [a,b,c]
public static String[] getLetters(String str){
return str.split("\\\\");
}
}
五、轉化雙向連結串列(二叉樹模板)
雙向連結串列節點結構和二叉樹節點結構是一樣的,如果你把last認為是left, next認為是next的話。
給定一個搜尋二叉樹的頭節點head,請轉化成一條有序的雙向連結串列,並返回連結串列的頭節點。
/**
* @Author: 郜宇博
* @Date: 2021/11/28 22:55
* 雙向連結串列節點結構和二叉樹節點結構是一樣的,如果你把last認為是left, next認為是next的話。
* 給定一個搜尋二叉樹的頭節點head,請轉化成一條有序的雙向連結串列,並返回鏈
* 表的頭節點。
*/
public class ConvertDoubleList {
public static void main(String[] args) {
Node head = new Node(5);
head.left = new Node(2);
head.right = new Node(9);
head.left.left = new Node(1);
head.left.right = new Node(3);
head.left.right.right = new Node(4);
head.right.left = new Node(7);
head.right.right = new Node(10);
head.left.left = new Node(1);
head.right.left.left = new Node(6);
head.right.left.right = new Node(8);
Node newHead = getDoubleLinkedList(head);
printDoubleLinkedList(newHead);
}
public static void printDoubleLinkedList(Node head) {
System.out.print("Double Linked List: ");
Node end = null;
while (head != null) {
System.out.print(head.value + " ");
end = head;
head = head.right;
}
System.out.print("| ");
while (end != null) {
System.out.print(end.value + " ");
end = end.left;
}
System.out.println();
}
public static class Node {
public int value;
public Node left;
public Node right;
public Node(int data) {
this.value = data;
}
}
static class Info{
public Node head;
public Node last;
public Info(Node head, Node last) {
this.head = head;
this.last = last;
}
}
public static Node getDoubleLinkedList(Node searchHead){
Info info = f(searchHead);
return info.head;
}
public static Info f(Node node){
if (node == null){
return new Info(null,null);
}
Info leftInfo = f(node.left);
Info rightInfo = f(node.right);
//連線
if (leftInfo.last != null){
leftInfo.last.right = node;
node.left = leftInfo.last;
}
if (rightInfo.head != null){
rightInfo.head.left = node;
node.right = rightInfo.head;
}
Node head = leftInfo.head==null?node:leftInfo.head;
Node last = rightInfo.last==null?node:rightInfo.last;
return new Info(head,last);
}
}
六、給定一個整型矩陣,返回子矩陣的最大累計和。
/**
* @Author: 郜宇博
* @Date: 2021/11/28 23:37
* 子矩陣最大和
*/
public class MaxChildMatrixSum {
public static void main(String[] args) {
int[][] matrix = { { -90, 48, 78 }, { 64, -40, 64 }, { -81, -7, 66 } };
System.out.println(getMaxMatrixSum(matrix));
}
/**
* 將矩陣的下面一行對應累加到上面,在求子陣列的累加和
*/
public static int getMaxMatrixSum(int[][] matrix){
if(matrix == null || matrix.length == 0){
return 0;
}
//將矩陣的上面層累加在一起方便求子陣列和,---》將矩陣求和變為一維陣列求和
int[] sumMatrixArray = null;
int cur = 0;
int max = Integer.MIN_VALUE;
for (int i = 0 ; i < matrix.length; i++){
sumMatrixArray = new int[matrix[0].length];
for (int j = i; j < matrix.length; j++){
//使用最大子陣列和
cur = 0;
for (int k = 0 ; k < matrix[0].length;k++){
//累加
sumMatrixArray[k] += matrix[j][k];
cur += sumMatrixArray[k];
max = Math.max(max,cur);
cur = Math.max(0,cur);
}
}
}
return max;
}
}