動態規劃。
以a字元為例,令 dp[i][j] 表示將從第 i 個 a 字元(包含)到第 j 個 a 字元(包含)之間的所有 a 字元移動到一起的交換次數,我們可以知道將所有的字元往中間移動的代價是最小的。
同時,假設從第 i + 1 個 a 字元到第 j - 1 個 a 字元之間的所有字元 a 都已經移動到一起了,無論它們的位置如何,則只需把 i 位置和 j 位置的 a 字元忘中間移動,即可得到把第 i 個 a 字元(包含)到第 之間的所有 到一起的最小操作次數,且該步驟的操作次數一定為第 j 個 a 字元的下標減去第 i 個 a 字元的下標加一再減第 i + 1 個 a 字元到第 j - 1 個 a 字元之間的所有字元 a 的數量。
package exam1.q4;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner sc = new Scanner(System.in);
int n, x;
n = sc.nextInt();
x = sc.nextInt();
long[] a = new long[n];
long min = Long.MAX_VALUE;
int startx = -1;
for(int i = 0; i < n; i++) {
a[i] = sc.nextInt();
if(a[i] < min) {
min = a[i];
}
}
x--;
sc.close();
for(int i = 0; i < n; i++) {
if(a[i] == min) {
int tmp = x - i;
if(tmp < 0)
tmp += n;
boolean f = true;
for(int j = 1; j <= tmp; j++) {
if(a[(i + j) % n] < min + 1){
f = false;
break;
}
}
if(f){
startx = i;
break;
}
}
}
long remain = 0;
if(x < startx)
remain = x + n - startx;
else
remain = x - startx;
long round = min;
for(int i = 0; i < n; i++)
a[i] -= round;
for(int i = 1; i <= remain; i++)
a[(startx + i) % n] -= 1;
a[startx] = round * n + remain;
for(int i = 0; i < n; i++)
System.out.print(a[i] + " ");
System.out.println();
}
}
複製程式碼
第五題:跳房子
題目
存在 n + 1 個房間,每個房間依次為房間 1 2 3…i,每個房間都存在一個傳送門,i房間的傳送門可以把人傳送到房間 pi(1<=pi<=i),現在路人甲從房間 1 開始出發(當前房間 1 即第一次訪問),每次移動他有兩種移動策略:
A. 如果訪問過當前房間 i 偶數次,那麼下一次移動到房間i+1;
B. 如果訪問過當前房間 i 奇數次,那麼移動到房間pi;
現在路人甲想知道移動到房間n+1一共需要多少次移動; 輸入描述:
第一行包括一個數字 n(30%資料1 <= n <= 100,100%資料 1 <= n <= 1000),表示房間的數量,接下來一行存在 n 個數字 pi(1 <= pi <= i), pi 表示從房間 i 可以傳送到房間 pi。 輸出描述:
輸出一行數字,表示最終移動的次數,最終結果需要對1000000007 (10e9 + 7) 取模。
package tideTheRoom;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.Scanner;
public class Main {
private static class Point implements Cloneable {
long x;
long y;
long a;
long b;
int cnt;
public Point(long x, long y, long a, long b, int cnt) {
super();
this.x = x;
this.y = y;
this.a = a;
this.b = b;
this.cnt = cnt;
}
public void rotate() {
if (this.cnt == 3)
return;
long tx = a - y + b;
long ty = x - a + b;
this.x = tx;
this.y = ty;
this.cnt++;
}
@Override
public Point clone() {
Object o = null;
try {
o = super.clone();
} catch (CloneNotSupportedException e) {
}
return (Point) o;
}
}
private static boolean check(Point[] p) {
long[] dist = new long[6];
int cnt = 0;
for (int i = 0; i < 3; i++) {
for (int j = i + 1; j < 4; j++) {
dist[cnt++] = (p[i].x - p[j].x) * (p[i].x - p[j].x) + (p[i].y - p[j].y) * (p[i].y - p[j].y);
}
}
Arrays.sort(dist);
if (dist[0] == dist[1] && dist[0] == dist[2] && dist[0] == dist[3] && dist[4] == dist[5]
&& !(dist[0] == dist[4]))
returntrue;
returnfalse;
}
private static int bfs(Point[] p) {
boolean[][][][] visited = new boolean[4][4][4][4];
LinkedList<Point[]> que = new LinkedList<>();
que.addLast(p);
visited[0][0][0][0] = true;
if (check(p))
return 0;
while (!que.isEmpty()) {
Point[] f = que.pollFirst();
for (int i = 0; i < 4; i++) {
Point[] tmp = new Point[4];
for (int j = 0; j < 4; j++) {
tmp[j] = f[j].clone();
}
tmp[i].rotate();
if (visited[tmp[0].cnt][tmp[1].cnt][tmp[2].cnt][tmp[3].cnt])
continue;
if (check(tmp)) {
return tmp[0].cnt + tmp[1].cnt + tmp[2].cnt + tmp[3].cnt;
}
que.addLast(tmp);
visited[tmp[0].cnt][tmp[1].cnt][tmp[2].cnt][tmp[3].cnt] = true;
}
}
return -1;
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
while ((n--) != 0) {
Point[] p = new Point[4];
for (int i = 0; i < 4; i++) {
long x = sc.nextLong();
long y = sc.nextLong();
long a = sc.nextLong();
long b = sc.nextLong();
p[i] = new Point(x, y, a, b, 0);
}
System.out.println(bfs(p));
}
sc.close();
}
}
複製程式碼
第二題:小易的字典
題目:
小易在學校中學習了關於字串的理論, 於是他基於此完成了一個字典的專案。
小易的這個字典很奇特, 字典內的每個單詞都包含n個’a’和m個’z’, 並且所有單詞按照字典序排列。
小易現在希望你能幫他找出第k個單詞是什麼。 輸入描述:
輸入包括一行三個整數n, m, k(1 <= n, m <= 100, 1 <= k <= 109), 以空格分割。
輸出描述:
出第k個字典中的字串,如果無解,輸出-1。
package dictionary;
import java.util.Scanner;
import static java.lang.Math.log;
import java.math.BigInteger;
import static java.lang.Math.exp;
public class Main {
public static long comb(int m, int n, long target) {// 計算假設a確定之後,a之後的部分排列組合數
if (m == 0 || n == 0)
return 1;
long sum = m + n;
long k = 1;
n = Math.min(m, n);// C(m+n) n=C(m+n) m 取最小即可
for (int i = 0; i < n; i++) {
k *= sum - i;
k /= (i + 1);
if (k > target)// 防止大數。如果k>target 則只進行list.add("a")和m--//a的個數減1。
// 沒有target -= k;因此不影響
break;
}
return k;
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int m = sc.nextInt();
int k = sc.nextInt();
int tn = n, tm = m;
StringBuilder sb = new StringBuilder();
while (tn > 0 && tm > 0) {
long c = comb(tn - 1, tm, k);
// System.out.println(c);
if (k <= c) {
sb.append('a');
tn--;
} else {
sb.append('z');
k -= c;
tm--;
}
}
if (k != 1)
System.out.println(-1);
else {
while (tn > 0) {
sb.append('a');
tn--;
}
while (tm > 0) {
sb.append('z');
tm--;
}
System.out.println(sb.toString());
}
sc.close();
}
}
複製程式碼
刷了一些LeetCode題
第一題:LeetCode 42 Trapping Rain Water 和 LeetCode 407 Trapping Rain Water II
Given n non-negative integers representing an elevation map where the width of each bar is 1, compute how much water it is able to trap after raining.
The above elevation map is represented by array [0,1,0,2,1,0,1,3,2,1,2,1]. In this case, 6 units of rain water (blue section) are being trapped. Thanks Marcos for contributing this image!
Example: Input:[0,1,0,2,1,0,1,3,2,1,2,1] Output: 6
題意
給 n 個柱子作為隔板,問柱子之間最多能存多少水
思路
根據木桶效應,能裝多少水是由左右兩邊最高的柱子中的最矮柱子來決定的。
我一開始的做法是用兩個陣列 maxHeightLeft 和 maxHeightRight 分別記錄位置 i 左邊的最高柱子和右邊的最高柱子。然後遍歷從 1 到 n – 2,
import java.lang.Math;
public class Solution {
public int trap(int[] height) {
int len = height.length;
int[] maxHeightLeft = new int[len];
int[] maxHeightRight = new int[len];
for(int i = 1; i < len; i ++){
if(height[i - 1] > maxHeightLeft[i - 1])
maxHeightLeft[i] = height[i - 1];
else
maxHeightLeft[i] = maxHeightLeft[i - 1];
}
for(int i = len - 2; i >= 0; i --) {
if(height[i + 1] > maxHeightRight[i + 1])
maxHeightRight[i] = height[i + 1];
else
maxHeightRight[i] = maxHeightRight[i + 1];
}
int sum = 0;
for(int i = 1; i < len - 1; i ++){
int shortEdge = Math.min(maxHeightLeft[i], maxHeightRight[i]);
if(shortEdge > height[i])
sum += shortEdge - height[i];
}
return sum;
}
}
複製程式碼
LeetCode 407 Trapping Rain Water II
Given an m x n matrix of positive integers representing the height of each unit cell in a 2D elevation map, compute the volume of water it is able to trap after raining.
Note:
Both m and n are less than 110. The height of each unit cell is greater than 0 and is less than 20,000.
Example:
Given the following 3×6 height map:
[
[1,4,3,1,3,2],
[3,2,1,3,2,4],
[2,3,3,2,3,1]
]
Return 4.
The above image represents the elevation map[[1,4,3,1,3,2],[3,2,1,3,2,4],[2,3,3,2,3,1]]before the rain.
After the rain, water is trapped between the blocks. The total volume of water trapped is 4.
import java.util.Comparator;
import java.util.PriorityQueue;
import static java.lang.Math.max;
public class Solution1 {
private final static int[][] steps = new int[][] { { 0, 1 }, { 0, -1 }, { 1, 0 }, { -1, 0 } };
private class Point {
int x;
int y;
int height;
public Point(int x, int y, int height) {
super();
this.x = x;
this.y = y;
this.height = height;
}
}
private class Comparator1 implements Comparator<Point> {
@Override
public int compare(Point o1, Point o2) {
if (o1.height > o2.height)
return 1;
return -1;
}
}
public int trapRainWater(int[][] heightMap) {
int ans = 0;
int lenx = heightMap.length;
if (lenx < 3)
return 0;
int leny = heightMap[0].length;
if (leny < 3)
return 0;
boolean[][] visited = new boolean[lenx][leny];
PriorityQueue<Point> que = new PriorityQueue<>(new Comparator1());
for (int i = 0; i < lenx; i++) {
que.add(new Point(i, 0, heightMap[i][0]));
visited[i][0] = true;
que.add(new Point(i, leny - 1, heightMap[i][leny - 1]));
visited[i][leny - 1] = true;
}
for (int i = 1; i < leny - 1; i++) {
que.add(new Point(0, i, heightMap[0][i]));
visited[0][i] = true;
que.add(new Point(lenx - 1, i, heightMap[lenx - 1][i]));
visited[lenx - 1][i] = true;
}
int maxHeight = -1;
while (!que.isEmpty()) {
Point cur = que.poll();
maxHeight = max(maxHeight, cur.height);
for (int i = 0; i < 4; i++) {
int nextX = cur.x + steps[i][0];
int nextY = cur.y + steps[i][1];
if (nextX >= 0 && nextX < lenx && nextY >= 0 && nextY < leny && !visited[nextX][nextY]) {
//System.out.println(nextX + " " + " " + nextY + " " + maxHeight + " " + heightMap[nextX][nextY]);
if (heightMap[nextX][nextY] < maxHeight) {
ans += maxHeight - heightMap[nextX][nextY];
}
visited[nextX][nextY] = true;
que.add(new Point(nextX, nextY, heightMap[nextX][nextY]));
}
}
}
return ans;
}
}
複製程式碼
第二題:leetcode 207 Course Schedule
題目
There are a total of n courses you have to take, labeled from 0 to n-1.
Some courses may have prerequisites, for example to take course 0 you have to first take course 1, which is expressed as a pair:[0,1]
Given the total number of courses and a list of prerequisite pairs, is it possible for you to finish all courses?
Example 1:
Input: 2, [[1,0]] Output: true Explanation: There are a total of 2 courses to take. To take course 1 you should have finished course 0. So it is possible.
Example 2:
Input: 2, [[1,0],[0,1]] Output: false Explanation: There are a total of 2 courses to take. To take course 1 you should have finished course 0, and to take course 0 you should also have finished course 1. So it is impossible.
Note:
The input prerequisites is a graph represented by a list of edges, not adjacency matrices. Read more about how a graph is represented.
You may assume that there are no duplicate edges in the input prerequisites.
思路
明顯的拓撲排序,複習一下,順便複習了一下圖的鏈式前向星表示法
程式碼
package leetcode_207_course_schedule;
import java.util.HashSet;
import java.util.Stack;
public class Solution {
private class Edge {
int next;
int to;
public Edge(int next, int to) {
super();
this.next = next;
this.to = to;
}
};
int[] head;
Edge[] edges;
int cntE;
public void add(int u, int v) {
Edge e = new Edge(head[u], v);
edges[++cntE] = e;
head[u] = cntE; // 第一條邊為當前邊
}
public boolean canFinish(int numCourses, int[][] prerequisites) {
Stack<Integer> stack = new Stack<>();
int len = prerequisites.length;
HashSet<Integer> set = new HashSet<>();
int[] indegree = new int[numCourses];
head = new int[numCourses];
edges = new Edge[len + 1];
for (int i = 0; i < len; i++) {
indegree[prerequisites[i][1]]++;
add(prerequisites[i][0], prerequisites[i][1]);
}
for (int i = 0; i < numCourses; i++) {
set.add(i);
}
for (int i = 0; i < numCourses; i++) {
if (indegree[i] == 0)
stack.add(i);
}
while (!stack.empty()) {
int cur = stack.pop();
set.remove(cur);
for (int i = head[cur]; i != 0; i = edges[i].next) {
indegree[edges[i].to]--;
if (indegree[edges[i].to] == 0)
stack.push(edges[i].to);
}
}
if (set.size() == 0)
returntrue;
elsereturnfalse;
}
}
複製程式碼
第三題:LeetCode 871 Minimum Number of Refueling Stops
A car travels from a starting position to a destination which is target miles east of the starting position.
Along the way, there are gas stations. Each station[i] represents a gas station that is station[i][0] miles east of the starting position, and has station[i][1] liters of gas.
The car starts with an infinite tank of gas, which initially has startFuel liters of fuel in it. It uses 1 liter of gas per 1 mile that it drives.
When the car reaches a gas station, it may stop and refuel, transferring all the gas from the station into the car.
What is the least number of refueling stops the car must make in order to reach its destination? If it cannot reach the destination, return -1.
Note that if the car reaches a gas station with 0 fuel left, the car can still refuel there. If the car reaches the destination with 0 fuel left, it is still considered to have arrived.
Example 1:
Input: target = 1, startFuel = 1, stations = [] Output: 0 Explanation: We can reach the target without refueling.
Example 2:
Input: target = 100, startFuel = 1, stations = [[10,100]] Output: -1 Explanation: We can’t reach the target (or even the first gas station).
Example 3:
Input: target = 100, startFuel = 10, stations = [[10,60],[20,30],[30,30],[60,40]] Output: 2 Explanation:
We start with 10 liters of fuel.
We drive to position 10, expending 10 liters of fuel. We refuel from 0 liters to 60 liters of gas.
Then, we drive from position 10 to position 60 (expending 50 liters of fuel),
and refuel from 10 liters to 50 liters of gas. We then drive to and reach the target.
We made 2 refueling stops along the way, so we return 2.
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.PriorityQueue;
public class Solution {
public class GasStation {
public int pos;
public int gas;
public GasStation(int pos, int gas) {
super();
this.pos = pos;
this.gas = gas;
}
}
class GasStationComparator1 implements Comparator<GasStation> {
@Override
public int compare(GasStation o1, GasStation o2) {
return o1.pos - o2.pos;
}
}
class GasStationComparator2 implements Comparator<GasStation> {
@Override
public int compare(GasStation o1, GasStation o2) {
return o2.gas - o1.gas;
}
}
public int minRefuelStops(int target, int startFuel, int[][] stations) {
int num_GS = stations.length;
List<GasStation> list = new ArrayList<>();
for (int[] gs : stations) {
list.add(new GasStation(gs[0], gs[1]));
}
list.add(new GasStation(target, 0));
list.sort(new GasStationComparator1());
int gas = startFuel;
PriorityQueue<GasStation> heap = new PriorityQueue<>(new GasStationComparator2());
int cnt = 0;
for (int i = 0; i < num_GS + 1; i++) {
GasStation gs = list.get(i);
if (gs.pos > gas) {
while (gs.pos > gas && !heap.isEmpty()) {
//System.out.println(heap.peek().pos + " " + heap.peek().gas);
gas += heap.poll().gas;
cnt++;
}
if (gs.pos > gas && heap.isEmpty()) {
return -1;
}
}
heap.add(gs);
}
return cnt;
}
}
複製程式碼