年輕即出發...
簡書:http://www.lxweimin.com/u/7110a2ba6f9e
知乎:https://www.zhihu.com/people/zqtao23/posts
GitHub源碼:https://github.com/zqtao2332
個人網站:http://www.zqtaotao.cn/ (停止維護更新內容)
QQ交流群:606939954
? 咆哮怪獸一枚...嗷嗷嗷...趁你現在還有時間,盡你自己最大的努力。努力做成你最想做的那件事,成為你最想成為的那種人,過著你最想過的那種生活。也許我們始終都只是一個小人物,但這并不妨礙我們選擇用什么樣的方式活下去,這個世界永遠比你想的要更精彩。
最后:喜歡編程,對生活充滿激情
本節內容預告
實例1:彩磚拼色
實例2:等差數列
實例3:01串
實例4:逆序n次
實例5:機器人走位
實例6:紙牌博弈
實例1:彩磚拼色
小易有一些彩色的磚塊。每種顏色由一個大寫字母表示。各個顏色磚塊看起來都完全一樣。
現在有一個給定的字符串s,s中每個字符代表小易的某個磚塊的顏色。
小易想把他所有的磚塊排成一行。
如果最多存在一對不同顏色的相鄰磚塊,那么這行磚塊就很漂亮的。
請你幫助小易計算有多少種方式將他所有磚塊排成漂亮的一行。(如果兩種方式所對應的磚塊顏色序列是相同的,那么認為這兩種方式是一樣的。)
例如: s= "ABAB",那么小易有六種排列的結果:'AABB", "ABAB", "ABBA", "ВAAВ", " ВАВА ", " ВВАА"其中只有"AABB"和"BBAA"滿足最多只有一對不同顏色的相鄰磚塊。
信息提取:
1、最多存在一對不同顏色的相鄰磚塊
顏色超過2中不滿足
2、相鄰磚塊成對
N 個磚塊,有 N-1對
3、篩選條件
1、顏色只有一種,返回1
2、顏色只有兩種,返回2
3、顏色超過2,返回0
import java.util.HashSet;
import java.util.Scanner;
import java.util.Set;
public class Code_15_ColorBrik {
public static int getColorBrik(String str) {
if (str == null || str.length() == 0) {
return 0;
}
Set<Character> set = new HashSet<>();
int res = 0;
for (char c : str.toCharArray()) {
if (!set.contains(c)){
set.add(c);
res++;
}
}
return res > 2 ? 0 : res;
}
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
String str = in.nextLine();
System.out.println(getColorBrik(str));
in.close();
}
}
實例2:等差數列
如果一個數列S滿足對于所有的合法的i,都有S[i + 1] = S[i] +d,這里的d也可以是負數和零,我們就稱數列S為等差數列。
小易現在有一個長度為n的數列x,小易想把x變為一個等差數列。
小易允許在數列上做交換任意兩個位置的數值的操作,并且交換操作允許交換多次。
但是有些數列通過交換還是不能變成等差數列,小易需要判別一個數列是否能通過交換操作變成等差數列
輸入描述:
輸入包括兩行,
第一行包含整數n(2 <n < 50),即數列的長度。
第二行n個元素x[i] (0 <x[i] < 1000),即數列中的每個整數。
思路:
利用等差數列求和公式
遍歷一遍數組求出幾個數據
sum 、n
同時找到最小值和次小值,算出 d
代入公式查看是否滿足等差數列的求和公式
import java.util.Scanner;
/**
* @description: 等差數列
*/
public class Code_16_ArithmeticSequence {
public static boolean isArithmeticSequence(int[] arr) {
if (arr == null || arr.length == 0) {
return false;
}
int sum = 0;
int min = Integer.MAX_VALUE;
for (int i = 0; i < arr.length; i++) {
sum += arr[i];
min = Math.min(min, arr[i]);
}
int n = arr.length;
if ((2 * (sum - min * n)) % (n * (n - 1)) == 0) { // d 可以為0 或是整數,%后為0
return true;
} else {
return false;
}
}
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int n = in.nextInt();
int[] arr = new int[n];
for (int i = 0; i < n; i++) {
arr[i] = in.nextInt();
}
if (isArithmeticSequence(arr))
System.out.println("Possible");
else
System.out.println("Impossible");
in.close();
}
}
實例3:01串
如果一個01串任意兩個相鄰位置的字符都是不一樣的,我們就叫這個01串為交錯01串。
例如: "1","10101","0101010"都是交錯01串。
小易現在有一個01串s,小易想找出一個最長的連續子串,并且這個子串是一個交錯01串。小易需要你幫幫忙求出最長的這樣的子串的長度是多少。
輸入描述:
輸入包括字符串s,
s的長度length(1 < length < 50),字符串中只包含'0'和'1
題目三擴展小易想找出一個最長的連續子串,并且這個子串是0和1數量相等的。該怎么做?
思路:
維護兩個變量,max:記錄最大長度, len: 記錄當前01串長度
比較 i 位置和 i-1位置,相同 len=0,不同len++
public static int max01Str(String str) {
if (str == null || str.length() == 0) return 0;
int max = 1;
int len = 1;
for (int i = 0; i < str.length(); i++) {
len++;
if (str.charAt(i) == str.charAt(i-1)){
len = 1;
}
max = Math.max(max, len);
}
return max;
}
擴展思路:
再次之前先回憶一下另外一道題
給定數組arr[] ,求子數組累加滿足給定值k的最長子數組長度。
http://www.lxweimin.com/p/431e9f9f7b74
此題,以某個位置為結尾的子數組,累加和為定值 k
public static int maxSubArrLen(int[] arr, int k) {
if (arr == null || arr.length == 0) return 0;
int len = 0;
int sum = 0;
HashMap<Integer, Integer> map = new HashMap<>();
map.put(0, -1); // 處理第一位等于 k 的情況
/*
6 1 2 3 k = 6
上來 sum = 6
sum - k = 0;
len = i - map.get(0) 但是現在不存在map.get(0) 這樣len返回的結果是0,而不是 1
*/
for (int i = 0; i < arr.length; i++) {
sum += arr[i];
if (map.containsKey(sum - k)) {
len = Math.max(len, i - map.get(sum - k));
}
if (!map.containsKey(sum)) {
map.put(sum, i);
}
}
return len;
}
現在再看擴展,將題目中的0全部置為 -1 ,那么原問題就變成了求 滿足子數組累加和為0 的最長子數組。
public static int max01Str2(String str) {
if (str == null || str.length() == 0) return 0;
HashMap<Integer, Integer> map = new HashMap<>();
map.put(0, -1);
int sum = 0;
int len = 0;
int k = 0; // 求滿足子數組累加等于0 的子數組長度
for (int i = 0; i < str.length(); i++) {
int cNum = (int) str.charAt(i) - '0';
sum += cNum;
if (map.containsKey(sum - k)){
len = Math.max(len, i - map.get(sum - k));
}
if (!map.containsKey(sum - k)){ // 不存在就添加
map.put(sum, i);
}
}
return len;
}
實例4:逆序n次
小易有一個長度為n的整數序列, a_1. .., an。然后考慮在一個空序列b上進行n次以下操作:1、將ai放入b序列的末尾2、逆置b序列小易需要你計算輸出操作n次之后的b序列。
輸入描述:輸入包括兩行,第一行包括一個整數n(2 第二行包括n個整數ai(1 < a_i < 10~9),即序列a中的每個整數,以空格分割
思路:雙端隊列
維護一個雙端隊列
每次添加都是先添加右邊在添加左邊
查看最后一次是添加在右邊還是添加在左邊,右邊,逆序,左邊,不逆序
import java.util.Arrays;
import java.util.Deque;
import java.util.LinkedList;
public class Code_18_NReverse {
public static int[] reverse(int[] arr) {
Deque<Integer> deque = new LinkedList<>();// 雙端隊列
boolean convert = false; // 標記是否需要逆序
for (int i = 0; i < arr.length; i++) {
if (convert) {
deque.addLast(arr[i]);
} else { // 不需要轉換就加入雙端隊列的尾部
deque.addFirst(arr[i]);
}
convert = !convert;
}
// 查看結果是否需要逆序
int i = 0;
if (convert) {
while (!deque.isEmpty())
arr[i++] = deque.pollFirst();
} else {
while (!deque.isEmpty()) {
arr[i++] = deque.pollLast();
}
}
return arr;
}
public static void main(String[] args) {
int[] arr = {1, 2, 3, 4, 5, 6};
reverse(arr);
System.out.println(Arrays.toString(arr));
}
}
實例5:機器人走位
一排有N個位置,一個機器人在最開始停留在P位置上,如果 p==0位置,下一分鐘機器人一定向右移動到1位置;如果p==N-1,下一分鐘機器人一定向左移動到N-2位置。如果P在0和N-1之間,下一分鐘機器人一定會向左或者向右移動。求K分鐘的時候,機器人到達位置有多少種走法。函數為: int f(int N, int P, int K, int T),返回值為走法的數量
public class Code_19_MachineRoad {
// 暴力嘗試
public static int f1(int N, int P, int K, int T) {
if (N < 2 || P < 0 || K < 1 || T < 0 || P >= N || T >= N) {
return 0; // 越界處理
}
if (K == 1) { // 一分鐘,一種或沒有
return T == P ? 1 : 0;
}
// 兩端位置
if (T == 0) {
return f1(N, P, K - 1, 1);
}
if (T == N - 1) {
return f1(N, P, K - 1, T - 1);
}
// 普遍位置
return f1(N, P, K - 1, T - 1) + f1(N, P, K - 1, T + 1);
}
// 動態規劃 一維表
public static int f2(int N, int P, int K, int T) {
if (N < 2 || P < 0 || K < 1 || T < 0 || P >= N || T >= N) {
return 0;
}
int[][] dp = new int[K][N];
dp[0][P] = 1;
for (int i = 1; i < K; i++) {
dp[i][0] = dp[i - 1][1];
dp[i][N - 1] = dp[i - 1][N - 2];
for (int j = 1; j < N - 1; j++) {
dp[i][j] = dp[i - 1][j - 1] + dp[i - 1][j + 1];
}
}
return dp[K - 1][T];
}
// 動態規劃 二維表
public static int f3(int N, int P, int K, int T) {
if (N < 2 || P < 0 || K < 1 || T < 0 || P >= N || T >= N) {
return 0;
}
int[] dp = new int[N];
dp[P] = 1;
int pre = 0;
int tmp = 0;
for (int i = 1; i < K; i++) {
pre = dp[0];
dp[0] = dp[1];
for (int j = 1; j < N - 1; j++) {
tmp = dp[j];
dp[j] = pre + dp[j + 1];
pre = tmp;
}
dp[N - 1] = pre;
}
return dp[T];
}
public static void main(String[] args) {
for (int i = 0; i < 300; i++) {
int N = (int) (Math.random() * 5) + 5;
int P = (int) (Math.random() * N);
int K = (int) (Math.random() * 10) + 2;
int T = (int) (Math.random() * N);
int res1 = f1(N, P, K, T);
int res2 = f2(N, P, K, T);
int res3 = f3(N, P, K, T);
if (res1 != res2 || res1 != res3) {
System.out.println("Fuck man!");
break;
}
}
}
}
實例6:紙牌博弈
排成一條線的紙牌博弈問題【題目】給定一個整型數組arr,代表數值不同的紙牌排成一條線。玩家 A和玩家B依次拿走每張紙牌,規定玩家A先拿,玩家B后拿,但是每個玩家每次只能拿走最左或最右的紙牌,玩家A和玩家B都絕頂聰明。請返回最后獲勝者的分數。【舉例】arr=[1, 2, 100, 4]。開始時玩家A只能拿走1或4。如果玩家A拿走1,則排列變為 2, 100, 4],接下來玩家B可以拿走2或4,然后繼續輪到玩家A。
public class Code_20_SelectedCards {
// 暴力嘗試
public static int win1(int[] arr) {
if (arr == null || arr.length == 0) {
return 0;
}
return Math.max(f(arr, 0, arr.length - 1), s(arr, 0, arr.length - 1));
}
public static int f(int[] arr, int i, int j) {
if (i == j) {
return arr[i];
}
return Math.max(arr[i] + s(arr, i + 1, j), arr[j] + s(arr, i, j - 1));
}
public static int s(int[] arr, int i, int j) {
if (i == j) {
return 0;
}
return Math.min(f(arr, i + 1, j), f(arr, i, j - 1));
}
// 單獨調用自己的暴力嘗試
public static int process(int[] arr, int i, int j) {
if (i == j) {
return arr[i];
}
if (i == j - 1) {
return Math.max(arr[i], arr[j]);
}
return Math.max(arr[i] + Math.min(process(arr, i + 2, j), process(arr, i + 1, j - 1)),
arr[j] + Math.min(process(arr, i + 1, j - 1), process(arr, i, j - 2))
);
}
// 動態規劃
public static int win2(int[] arr) {
if (arr == null || arr.length == 0) {
return 0;
}
int[][] f = new int[arr.length][arr.length];
int[][] s = new int[arr.length][arr.length];
for (int j = 0; j < arr.length; j++) {
f[j][j] = arr[j];
for (int i = j - 1; i >= 0; i--) {
f[i][j] = Math.max(arr[i] + s[i + 1][j], arr[j] + s[i][j - 1]);
s[i][j] = Math.min(f[i + 1][j], f[i][j - 1]);
}
}
return Math.max(f[0][arr.length - 1], s[0][arr.length - 1]);
}
public static void main(String[] args) {
int[] arr = { 1, 9, 1 };
System.out.println(win1(arr));
System.out.println(win2(arr));
}
}