年輕即出發(fā)...
簡書:http://www.lxweimin.com/u/7110a2ba6f9e
知乎:https://www.zhihu.com/people/zqtao23/posts
GitHub源碼:https://github.com/zqtao2332
個(gè)人網(wǎng)站:http://www.zqtaotao.cn/ (停止維護(hù)更新內(nèi)容)
QQ交流群:606939954
? 咆哮怪獸一枚...嗷嗷嗷...趁你現(xiàn)在還有時(shí)間,盡你自己最大的努力。努力做成你最想做的那件事,成為你最想成為的那種人,過著你最想過的那種生活。也許我們始終都只是一個(gè)小人物,但這并不妨礙我們選擇用什么樣的方式活下去,這個(gè)世界永遠(yuǎn)比你想的要更精彩。
最后:喜歡編程,對生活充滿激情
本節(jié)內(nèi)容預(yù)告
實(shí)例1:彩磚拼色
實(shí)例2:等差數(shù)列
實(shí)例3:01串
實(shí)例4:逆序n次
實(shí)例5:機(jī)器人走位
實(shí)例6:紙牌博弈
實(shí)例1:彩磚拼色
小易有一些彩色的磚塊。每種顏色由一個(gè)大寫字母表示。各個(gè)顏色磚塊看起來都完全一樣。
現(xiàn)在有一個(gè)給定的字符串s,s中每個(gè)字符代表小易的某個(gè)磚塊的顏色。
小易想把他所有的磚塊排成一行。
如果最多存在一對不同顏色的相鄰磚塊,那么這行磚塊就很漂亮的。
請你幫助小易計(jì)算有多少種方式將他所有磚塊排成漂亮的一行。(如果兩種方式所對應(yīng)的磚塊顏色序列是相同的,那么認(rèn)為這兩種方式是一樣的。)
例如: s= "ABAB",那么小易有六種排列的結(jié)果:'AABB", "ABAB", "ABBA", "ВAAВ", " ВАВА ", " ВВАА"其中只有"AABB"和"BBAA"滿足最多只有一對不同顏色的相鄰磚塊。
信息提取:
1、最多存在一對不同顏色的相鄰磚塊
顏色超過2中不滿足
2、相鄰磚塊成對
N 個(gè)磚塊,有 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();
}
}
實(shí)例2:等差數(shù)列
如果一個(gè)數(shù)列S滿足對于所有的合法的i,都有S[i + 1] = S[i] +d,這里的d也可以是負(fù)數(shù)和零,我們就稱數(shù)列S為等差數(shù)列。
小易現(xiàn)在有一個(gè)長度為n的數(shù)列x,小易想把x變?yōu)橐粋€(gè)等差數(shù)列。
小易允許在數(shù)列上做交換任意兩個(gè)位置的數(shù)值的操作,并且交換操作允許交換多次。
但是有些數(shù)列通過交換還是不能變成等差數(shù)列,小易需要判別一個(gè)數(shù)列是否能通過交換操作變成等差數(shù)列
輸入描述:
輸入包括兩行,
第一行包含整數(shù)n(2 <n < 50),即數(shù)列的長度。
第二行n個(gè)元素x[i] (0 <x[i] < 1000),即數(shù)列中的每個(gè)整數(shù)。
思路:
利用等差數(shù)列求和公式
遍歷一遍數(shù)組求出幾個(gè)數(shù)據(jù)
sum 、n
同時(shí)找到最小值和次小值,算出 d
代入公式查看是否滿足等差數(shù)列的求和公式
import java.util.Scanner;
/**
* @description: 等差數(shù)列
*/
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 或是整數(shù),%后為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();
}
}
實(shí)例3:01串
如果一個(gè)01串任意兩個(gè)相鄰位置的字符都是不一樣的,我們就叫這個(gè)01串為交錯(cuò)01串。
例如: "1","10101","0101010"都是交錯(cuò)01串。
小易現(xiàn)在有一個(gè)01串s,小易想找出一個(gè)最長的連續(xù)子串,并且這個(gè)子串是一個(gè)交錯(cuò)01串。小易需要你幫幫忙求出最長的這樣的子串的長度是多少。
輸入描述:
輸入包括字符串s,
s的長度length(1 < length < 50),字符串中只包含'0'和'1
題目三擴(kuò)展小易想找出一個(gè)最長的連續(xù)子串,并且這個(gè)子串是0和1數(shù)量相等的。該怎么做?
思路:
維護(hù)兩個(gè)變量,max:記錄最大長度, len: 記錄當(dāng)前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;
}
擴(kuò)展思路:
再次之前先回憶一下另外一道題
給定數(shù)組arr[] ,求子數(shù)組累加滿足給定值k的最長子數(shù)組長度。
http://www.lxweimin.com/p/431e9f9f7b74
此題,以某個(gè)位置為結(jié)尾的子數(shù)組,累加和為定值 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) 但是現(xiàn)在不存在map.get(0) 這樣len返回的結(jié)果是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;
}
現(xiàn)在再看擴(kuò)展,將題目中的0全部置為 -1 ,那么原問題就變成了求 滿足子數(shù)組累加和為0 的最長子數(shù)組。
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; // 求滿足子數(shù)組累加等于0 的子數(shù)組長度
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;
}
實(shí)例4:逆序n次
小易有一個(gè)長度為n的整數(shù)序列, a_1. .., an。然后考慮在一個(gè)空序列b上進(jìn)行n次以下操作:1、將ai放入b序列的末尾2、逆置b序列小易需要你計(jì)算輸出操作n次之后的b序列。
輸入描述:輸入包括兩行,第一行包括一個(gè)整數(shù)n(2 第二行包括n個(gè)整數(shù)ai(1 < a_i < 10~9),即序列a中的每個(gè)整數(shù),以空格分割
思路:雙端隊(duì)列
維護(hù)一個(gè)雙端隊(duì)列
每次添加都是先添加右邊在添加左邊
查看最后一次是添加在右邊還是添加在左邊,右邊,逆序,左邊,不逆序
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<>();// 雙端隊(duì)列
boolean convert = false; // 標(biāo)記是否需要逆序
for (int i = 0; i < arr.length; i++) {
if (convert) {
deque.addLast(arr[i]);
} else { // 不需要轉(zhuǎn)換就加入雙端隊(duì)列的尾部
deque.addFirst(arr[i]);
}
convert = !convert;
}
// 查看結(jié)果是否需要逆序
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));
}
}
實(shí)例5:機(jī)器人走位
一排有N個(gè)位置,一個(gè)機(jī)器人在最開始停留在P位置上,如果 p==0位置,下一分鐘機(jī)器人一定向右移動到1位置;如果p==N-1,下一分鐘機(jī)器人一定向左移動到N-2位置。如果P在0和N-1之間,下一分鐘機(jī)器人一定會向左或者向右移動。求K分鐘的時(shí)候,機(jī)器人到達(dá)位置有多少種走法。函數(shù)為: int f(int N, int P, int K, int T),返回值為走法的數(shù)量
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);
}
// 動態(tài)規(guī)劃 一維表
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];
}
// 動態(tài)規(guī)劃 二維表
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;
}
}
}
}
實(shí)例6:紙牌博弈
排成一條線的紙牌博弈問題【題目】給定一個(gè)整型數(shù)組arr,代表數(shù)值不同的紙牌排成一條線。玩家 A和玩家B依次拿走每張紙牌,規(guī)定玩家A先拿,玩家B后拿,但是每個(gè)玩家每次只能拿走最左或最右的紙牌,玩家A和玩家B都絕頂聰明。請返回最后獲勝者的分?jǐn)?shù)。【舉例】arr=[1, 2, 100, 4]。開始時(shí)玩家A只能拿走1或4。如果玩家A拿走1,則排列變?yōu)?2, 100, 4],接下來玩家B可以拿走2或4,然后繼續(xù)輪到玩家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));
}
// 單獨(dú)調(diào)用自己的暴力嘗試
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))
);
}
// 動態(tài)規(guī)劃
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));
}
}