題目描述
一個應用啟動時,會有多個初始化任務需要執行,並且任務之間有依賴關係,例如A任務依賴B任務,那麼必須在B任務執行完成之後,才能開始執行A任務。
現在給出多條任務依賴關係的規則,請輸入任務的順序執行序列,規則採用貪婪策略,即一個任務如果沒有依賴的任務,則立刻開始執行,如果同時有多個任務要執行,則根據任務名稱字母順序排序。
例如:B任務依賴A任務,C任務依賴A任務,D任務依賴B任務和C任務,同時,D任務還依賴E任務。那麼執行任務的順序由先到後是:
A任務,E任務,B任務,C任務,D任務
這裡A和E任務都是沒有依賴的,立即執行。
輸入描述
輸入引數每個元素都表示任意兩個任務之間的依賴關係,輸入引數中符號"->"表示依賴方向,例如:
A->B:表示A依賴B
多個依賴之間用單個空格分隔
輸出描述
輸出排序後的啟動任務列表,多個任務之間用單個空格分隔
用例
輸入
A->B C->B
輸出
B A C
要解決這個任務排程問題,可以使用拓撲排序(Topological Sorting),這是一種在有向無環圖(DAG)中排序頂點的方法,以確保每個頂點都在其所有依賴頂點之後。
下面是如何使用 Java 來實現這個問題的解決方案:
解決方案步驟
- 解析輸入:將任務依賴關係轉化為圖的鄰接表和入度表。
- 執行拓撲排序:使用貪婪策略(優先佇列)來進行排序。
Java 實現
import java.util.*;
public class TaskScheduler {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
String input = scanner.nextLine();
scanner.close();
// 1. Parse input
Map<Character, List<Character>> graph = new HashMap<>();
Map<Character, Integer> inDegree = new HashMap<>();
Set<Character> allTasks = new HashSet<>();
for (String relation : input.split(" ")) {
char from = relation.charAt(0);
char to = relation.charAt(3);
// Initialize graph and inDegree map
graph.putIfAbsent(from, new ArrayList<>());
graph.putIfAbsent(to, new ArrayList<>());
inDegree.putIfAbsent(from, 0);
inDegree.putIfAbsent(to, 0);
// Build graph and inDegree count
graph.get(from).add(to);
inDegree.put(to, inDegree.get(to) + 1);
allTasks.add(from);
allTasks.add(to);
}
// 2. Topological sort using a priority queue for lexicographical order
PriorityQueue<Character> zeroInDegreeQueue = new PriorityQueue<>();
for (char task : allTasks) {
if (inDegree.get(task) == 0) {
zeroInDegreeQueue.offer(task);
}
}
StringBuilder result = new StringBuilder();
while (!zeroInDegreeQueue.isEmpty()) {
char current = zeroInDegreeQueue.poll();
result.append(current).append(" ");
for (char neighbor : graph.get(current)) {
inDegree.put(neighbor, inDegree.get(neighbor) - 1);
if (inDegree.get(neighbor) == 0) {
zeroInDegreeQueue.offer(neighbor);
}
}
}
// Output result
System.out.println(result.toString().trim());
}
}
解釋
-
輸入解析:
- 透過分割輸入字串並解析依賴關係來構建圖和入度表。
graph
是一個鄰接表,表示每個任務的依賴任務。inDegree
是一個入度表,記錄每個任務的依賴數。
-
拓撲排序:
- 使用一個優先佇列(
PriorityQueue
)來保證每次取出的任務是字母順序的最小值。 - 從入度為 0 的任務開始處理,每次從佇列中取出一個任務,更新其所有依賴任務的入度。如果依賴任務的入度變為 0,則將其加入佇列。
- 使用一個優先佇列(
-
輸出結果:
- 輸出排序後的任務列表。
這種方法可以處理複雜的依賴關係,並保證任務執行的正確順序。
題目描述
有 N 塊二手市場收集的銀飾,每塊銀飾的重量都是正整數,收集到的銀飾會被熔化用於打造新的飾品。 每一回合,從中選出三塊 最重的 銀飾,然後一起熔掉。假設銀飾的重量分別為 x 、y 和 z,且 x <= y <= z。那麼熔掉的可能結果如下:
如果x == y == z,那麼三塊銀飾都會被完全熔掉;
如果x == y且y != z,會剩餘重量為z - y的銀塊無法被熔掉;
如果x != y且y == z,會剩餘重量為y - x的銀塊無法被熔掉;
如果x != y且y != z,會剩餘重量為z - y與y - x差值的銀塊無法被熔掉。
如果剩餘兩塊,返回較大的重量(若兩塊重量相同,返回任意一塊皆可);如果只剩下一塊,返回該塊的重量;如果沒有剩下,就返回 0。
輸入描述
輸入資料為兩行
第一行為銀飾陣列長度 n,1 ≤ n ≤ 40,
第二行為 n 塊銀飾的重量,重量的取值範圍為[1,2000],重量之間使用空格隔開
輸出描述
如果剩餘兩塊,返回較大的重量(若兩塊重量相同,返回任意一塊皆可);如果只剩下一塊,返回該塊的重量;如果沒有剩下,就返回 0。
為了實現這個問題,我們需要一個貪婪演算法來不斷從銀飾中選擇最重的三塊進行處理,直到沒有足夠的銀飾可處理為止。以下是實現的詳細步驟:
- 解析輸入:將輸入的銀飾重量資料儲存到一個列表中。
- 處理三塊銀飾:每次選擇列表中最重的三塊銀飾進行處理,並根據題目規則更新銀飾列表。
- 處理剩餘銀飾:在沒有足夠的銀飾進行處理時,根據剩餘銀飾的數量決定返回的結果。
實現步驟
- 選擇三塊最重的銀飾。
- 按照規則進行處理:
- 如果三塊銀飾的重量相同,則全部熔掉。
- 如果兩塊銀飾的重量相同,剩餘的重量需要被更新。
- 否則,計算並更新剩餘的重量。
- 返回最終結果:
- 如果剩下兩塊,返回較大的重量。
- 如果只剩下一塊,返回該塊的重量。
- 如果沒有剩餘,返回0。
Java 實現程式碼
import java.util.*;
public class SilverProcessing {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
// 讀取銀飾的數量
int n = scanner.nextInt();
List<Integer> silverWeights = new ArrayList<>();
// 讀取銀飾的重量
for (int i = 0; i < n; i++) {
silverWeights.add(scanner.nextInt());
}
scanner.close();
// 持續處理銀飾直到剩餘不足三塊
while (silverWeights.size() >= 3) {
// 對銀飾重量進行排序
Collections.sort(silverWeights);
// 取出最重的三塊銀飾
int z = silverWeights.remove(silverWeights.size() - 1);
int y = silverWeights.remove(silverWeights.size() - 1);
int x = silverWeights.remove(silverWeights.size() - 1);
if (x == y && y == z) {
// 情況1: x == y == z
// 不需要做任何事情,三塊銀飾都被完全熔掉
} else if (x == y) {
// 情況2: x == y && y != z
if (z - y > 0) {
silverWeights.add(z - y);
}
} else if (y == z) {
// 情況3: x != y && y == z
if (y - x > 0) {
silverWeights.add(y - x);
}
} else {
// 情況4: x != y && y != z
int diff1 = z - y;
int diff2 = y - x;
if (diff1 > 0) {
silverWeights.add(diff1);
}
if (diff2 > 0) {
silverWeights.add(diff2);
}
}
// 對更新後的銀飾列表排序
Collections.sort(silverWeights);
}
// 輸出剩餘銀飾的重量
if (silverWeights.size() == 2) {
System.out.println(Math.max(silverWeights.get(0), silverWeights.get(1)));
} else if (silverWeights.size() == 1) {
System.out.println(silverWeights.get(0));
} else {
System.out.println(0);
}
}
}
程式碼解釋
- 輸入處理:從標準輸入讀取銀飾的數量和重量,並儲存在
silverWeights
列表中。 - 處理銀飾:
- 排序銀飾列表,取出最重的三塊。
- 根據不同的規則更新銀飾列表。
- 將剩餘的重量重新插入列表並排序。
- 結果輸出:根據剩餘銀飾的數量決定輸出。
注意事項
- 程式碼使用了
Collections.sort()
進行排序以獲取最重的三塊銀飾。 - 當列表的大小小於三時,退出處理並根據剩餘的數量輸出結果。
題目描述:
特定大小的停車場,陣列cars[]表示,其中1表示有車,0表示沒車。車輛大小不一,小車佔一個車位(長度1),貨車佔兩個車位(長度2),卡車佔三個車位(長度3),統計停車場最少可以停多少輛車,返回具體的數目。
輸入描述:
整型字串陣列cars[],其中1表示有車,0表示沒車,陣列長度小於1000。
輸出描述:
整型數字字串,表示最少停車數目。
補充說明:
示例1
輸入:
1,0,1
輸出:
2
說明:
1個小車佔第1個車位
第二個車位空
1個小車佔第3個車位
最少有兩輛車
示例2
輸入:
1,1,0,0,1,1,1,0,1
輸出:
3
說明:
1個貨車佔第1、2個車位
第3、4個車位空
1個卡車佔第5、6、7個車位
第8個車位空
1個小車佔第9個車位
最少3輛車
為了計算停車場中最少可以停多少輛車,我們需要考慮不同大小的車輛(小車、貨車、卡車)的停放規則,並儘可能利用停車位以最小化車輛數量。具體思路如下:
- 解析輸入:將停車場的車位狀態轉換為整數陣列。
- 車輛停放策略:
- 優先放置最大的車輛(卡車),因為它們需要更多的連續空間。
- 接著放置中等大小的車輛(貨車)。
- 最後放置最小的車輛(小車)。
- 計算停車位使用情況:
- 遍歷陣列,從左到右檢測連續的空位,並嘗試放置儘可能大的車輛。
- 更新停車位狀態,繼續處理剩餘的空位。
Java 實現程式碼
import java.util.Arrays;
public class ParkingLot {
public static void main(String[] args) {
String input = "1,1,0,0,1,1,1,0,1";
int[] cars = Arrays.stream(input.split(","))
.mapToInt(Integer::parseInt)
.toArray();
System.out.println(minimumCars(cars));
}
public static int minimumCars(int[] cars) {
int count = 0;
int n = cars.length;
int i = 0;
while (i < n) {
if (cars[i] == 1) {
// Find the length of the continuous segment of 1s
int start = i;
while (i < n && cars[i] == 1) {
i++;
}
int length = i - start;
// First try to place the largest vehicle (size 3)
if (length >= 3) {
count += length / 3;
length %= 3;
}
// Then try to place the medium vehicle (size 2)
if (length >= 2) {
count += length / 2;
length %= 2;
}
// Finally place the smallest vehicle (size 1)
if (length == 1) {
count += 1;
}
} else {
i++;
}
}
return count;
}
}
程式碼解釋
-
輸入處理:
- 將輸入的字串按逗號分隔,並轉換為整數陣列
cars
。
- 將輸入的字串按逗號分隔,並轉換為整數陣列
-
處理停車位:
- 使用
while
迴圈遍歷cars
陣列,找到連續的1
代表的空位段。 - 計算該段的長度,並依次嘗試放置最大的車輛(卡車)、中等車輛(貨車)、最小車輛(小車)。
- 更新剩餘的空位長度,繼續處理下一個段落。
- 使用
-
輸出結果:
- 返回計算出的最少車輛數。
示例說明
- 對於輸入
1,1,0,0,1,1,1,0,1
:- 找到連續的
1
段:1,1
(貨車),1,1,1
(卡車),1
(小車)。 - 最終需要的車輛數量是:1 貨車 + 1 卡車 + 1 小車 = 3。
- 找到連續的
這種方法保證了透過貪婪策略最小化車輛數量,並且適用於長度不超過 1000 的停車場陣列。
題目描述
輸入字串s,輸出s中包含所有整數的最小和。
說明:
字串s,只包含 a-z A-Z ± ;
合法的整數包括
1) 正整數 一個或者多個0-9組成,如 0 2 3 002 102
2)負整數 負號 – 開頭,數字部分由一個或者多個0-9組成,如 -0 -012 -23 -00023
輸入描述
包含數字的字串
輸出描述
所有整數的最小和
用例
輸入
bb1234aa
輸出
10
說明
無
輸入
bb12-34aa
輸出
-31
說明
1+2+(-34) = -31
為了處理這個問題,我們需要從字串中提取所有的整數,然後計算這些整數的總和。以下是解決此問題的詳細步驟和 Java 實現程式碼:
解決步驟
-
提取整數:
- 使用正規表示式從字串中提取所有的整數。正規表示式可以用來匹配正整數和負整數。
-
轉換和累加:
- 將提取出的字串形式的整數轉換為實際的整數型別。
- 計算這些整數的和。
Java 實現程式碼
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class MinimumSumOfIntegers {
public static void main(String[] args) {
// 示例輸入
String input = "bb12-34aa";
System.out.println(minimumSum(input));
}
public static int minimumSum(String s) {
// 使用正規表示式提取所有整數,包括負整數
Pattern pattern = Pattern.compile("[-]?\\d+");
Matcher matcher = pattern.matcher(s);
int sum = 0;
// 遍歷匹配到的整數
while (matcher.find()) {
// 將匹配到的字串轉換為整數
int number = Integer.parseInt(matcher.group());
// 累加到總和
sum += number;
}
return sum;
}
}
程式碼解釋
-
正規表示式:
[-]?\\d+
:匹配負號(可選)後面跟隨的一個或多個數字。這樣可以提取正整數和負整數。
-
提取和計算:
Pattern
和Matcher
類用於從字串中提取符合正規表示式的部分。matcher.find()
用於逐一查詢匹配的整數,並用matcher.group()
提取匹配的字串。Integer.parseInt()
將匹配的字串轉換為整數並累加到sum
。
示例解析
-
輸入:
"bb12-34aa"
- 匹配到的整數為
12
和-34
。 - 計算和為
12 + (-34) = -22
。
- 匹配到的整數為
-
輸入:
"bb1234aa"
- 匹配到的整數為
1234
。 - 計算和為
1234
。
- 匹配到的整數為
這個方法能夠處理輸入字串中所有合法的整數,確保了對整數的正確提取和計算。
題目描述
提取字串中的最長合法簡單數學表示式,字串長度最長的,並計算表示式的值。
如果沒有,則返回0。 簡單數學表示式只能包含以下內容:0-9數字,符號 +-*
說明:
-
所有數字,計算結果都不超過long
-
如果有多個長度一樣的,請返回第一個表示式的結果
-
數學表示式,必須是最長的,合法的
-
運算子不能連續出現,如 +--+1 是不合法的
輸入
字串
輸出
表示式值
樣例輸入
1-2abcd
樣例輸出
-1
要解決這個問題,我們需要從給定的字串中提取所有合法的數學表示式,找到最長的那個,然後計算它的值。以下是解決該問題的詳細步驟和 Java 實現程式碼:
解決步驟
-
提取合法數學表示式:
- 使用正規表示式從字串中提取合法的數學表示式。
- 合法的數學表示式只能包含數字、加號(
+
)、減號(-
)和乘號(*
),且運算子不能連續出現。
-
驗證表示式的合法性:
- 確保提取的表示式合法,沒有連續的運算子。
-
計算表示式的值:
- 使用 Java 的表示式計算器
ScriptEngine
來計算數學表示式的值。
- 使用 Java 的表示式計算器
-
返回結果:
- 找到最長的合法表示式並計算其值。如果沒有合法表示式,返回0。
Java 實現程式碼
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class LongestMathExpression {
public static void main(String[] args) {
// 示例輸入
String input = "1-2abcd";
System.out.println(evaluateLongestExpression(input));
}
public static long evaluateLongestExpression(String s) {
// 使用正規表示式提取所有合法的數學表示式
Pattern pattern = Pattern.compile("[0-9]+([+*/-][0-9]+)*");
Matcher matcher = pattern.matcher(s);
String longestExpression = "";
// 遍歷匹配到的表示式
while (matcher.find()) {
String expr = matcher.group();
// 更新最長表示式
if (expr.length() > longestExpression.length()) {
longestExpression = expr;
}
}
if (longestExpression.isEmpty()) {
return 0; // 沒有找到合法的表示式
}
// 計算最長合法表示式的值
try {
ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = manager.getEngineByName("JavaScript");
return ((Number) engine.eval(longestExpression)).longValue();
} catch (ScriptException e) {
e.printStackTrace();
return 0; // 計算錯誤,返回0
}
}
}
程式碼解釋
-
正規表示式:
"[0-9]+([+*/-][0-9]+)*"
:匹配由數字和運算子(+
,-
,*
,/
)組成的合法數學表示式,不允許運算子連續出現。
-
提取和更新最長表示式:
matcher.find()
用於查詢所有符合條件的表示式。- 根據長度更新最長的合法表示式。
-
計算表示式的值:
- 使用
ScriptEngine
來計算表示式的值。ScriptEngine
是 Java 提供的一個功能,可以用來執行 JavaScript 程式碼,從而評估數學表示式。 - 處理
ScriptException
以確保計算錯誤時返回0。
- 使用
-
返回結果:
- 返回最長合法數學表示式的計算結果。如果沒有找到合法表示式,則返回0。
示例解析
-
輸入:
"1-2abcd"
- 匹配到的合法數學表示式為
1-2
。 - 計算
1-2
的結果為-1
。
- 匹配到的合法數學表示式為
-
輸入:
"a1+2b-3*4"
- 匹配到的合法數學表示式為
1+2-3*4
。 - 計算
1+2-3*4
的結果為-9
。
- 匹配到的合法數學表示式為
題目描述
有一種特殊的加密演算法,明文為一段數字串,經過密碼本查詢轉換,生成另一段密文數字串。
規則如下:
明文為一段數字串由 0~9 組成
密碼本為數字 0~9 組成的二維陣列
需要按明文串的數字順序在密碼本里找到同樣的數字串,密碼本里的數字串是由相鄰的單元格數字組成,上下和左右是相鄰的,注意:對角線不相鄰,同一個單元格的數字不能重複使用。
每一位明文對應密文即為密碼本中找到的單元格所在的行和列序號(序號從0開始)組成的兩個數宇。
如明文第 i 位 Data[i] 對應密碼本單元格為 Book[x][y],則明文第 i 位對應的密文為X Y,X和Y之間用空格隔開。
如果有多條密文,返回字元序最小的密文。
如果密碼本無法匹配,返回"error"。
請你設計這個加密程式。
示例1:
密碼本:
0 0 2
1 3 4
6 6 4
明文:"3",密文:"1 1"
示例2:
密碼本:
0 0 2
要解決這個問題,我們需要設計一個程式,根據明文串從密碼本中找到對應的密文。我們要遍歷密碼本以找到明文的每個數字,並且根據規則輸出其對應的座標。如果沒有找到匹配的密文,則返回 "error"
。為了確保匹配的結果按字典序最小,我們需要在遍歷密碼本時進行排序。
解決步驟
-
遍歷密碼本:
- 對密碼本進行遍歷,找到每個數字的位置。我們需要記錄每個數字的位置,並且需要保證搜尋過程儘可能快,以找到字典序最小的密文。
-
查詢路徑:
- 對於明文中的每個數字,嘗試找到在密碼本中相鄰的數字序列。如果明文的數字串可以在密碼本中找到相應的序列,那麼記錄下這些位置。
-
生成密文:
- 根據找到的路徑生成密文。每個數字的位置被轉化為
(行, 列)
的格式。如果有多條密文,選擇字典序最小的。
- 根據找到的路徑生成密文。每個數字的位置被轉化為
-
返回結果:
- 如果找到了合法的密文,輸出最小的密文。如果沒有找到,返回
"error"
。
- 如果找到了合法的密文,輸出最小的密文。如果沒有找到,返回
Java 實現程式碼
import java.util.*;
public class Encryption {
public static void main(String[] args) {
// 示例輸入
int[][] book = {
{0, 0, 2},
{1, 3, 4},
{6, 6, 4}
};
String plaintext = "3";
// 輸出結果
System.out.println(findMinimumCipher(book, plaintext));
}
public static String findMinimumCipher(int[][] book, String plaintext) {
int rows = book.length;
int cols = book[0].length;
Map<Character, List<int[]>> positions = new HashMap<>();
// 記錄每個數字的所有位置
for (int r = 0; r < rows; r++) {
for (int c = 0; c < cols; c++) {
char num = (char) (book[r][c] + '0');
if (!positions.containsKey(num)) {
positions.put(num, new ArrayList<>());
}
positions.get(num).add(new int[]{r, c});
}
}
// 從明文開始構建可能的密文
return findMinCipher(positions, plaintext, book);
}
private static String findMinCipher(Map<Character, List<int[]>> positions, String plaintext, int[][] book) {
List<int[]> currentPath = new ArrayList<>();
for (int i = 0; i < plaintext.length(); i++) {
char digit = plaintext.charAt(i);
if (!positions.containsKey(digit)) {
return "error";
}
List<int[]> possiblePositions = positions.get(digit);
if (currentPath.isEmpty()) {
currentPath.addAll(possiblePositions);
} else {
List<int[]> nextPath = new ArrayList<>();
for (int[] prev : currentPath) {
for (int[] pos : possiblePositions) {
if (isAdjacent(prev, pos)) {
nextPath.add(pos);
}
}
}
if (nextPath.isEmpty()) {
return "error";
}
Collections.sort(nextPath, (a, b) -> {
if (a[0] != b[0]) return a[0] - b[0];
return a[1] - b[1];
});
currentPath = nextPath;
}
}
if (currentPath.isEmpty()) {
return "error";
}
Collections.sort(currentPath, (a, b) -> {
if (a[0] != b[0]) return a[0] - b[0];
return a[1] - b[1];
});
StringBuilder sb = new StringBuilder();
for (int[] pos : currentPath) {
sb.append(pos[0]).append(" ").append(pos[1]).append(" ");
}
return sb.toString().trim();
}
private static boolean isAdjacent(int[] pos1, int[] pos2) {
int r1 = pos1[0], c1 = pos1[1];
int r2 = pos2[0], c2 = pos2[1];
return (r1 == r2 && Math.abs(c1 - c2) == 1) || (c1 == c2 && Math.abs(r1 - r2) == 1);
}
}
程式碼解釋
-
記錄數字位置:
- 使用
Map<Character, List<int[]>>
來記錄每個數字在密碼本中的所有位置。
- 使用
-
路徑查詢:
- 對於每個數字,從
plaintext
中提取的位置,檢查是否可以連線到之前的數字。如果可以,將位置新增到nextPath
列表中。
- 對於每個數字,從
-
排序:
- 在每步中對路徑進行排序,以確保生成的密文是字典序最小的。
-
計算結果:
- 生成最終的密文,格式為
行 列
,並返回。如果無法匹配任何密文,返回"error"
。
- 生成最終的密文,格式為
這段程式碼解決了如何在密碼本中查詢並生成合法的密文,同時確保結果是字典序最小的。
題目描述:
有一個檔案, 包含以一定規則寫作的文字, 請統計檔案中包含的文字數量
規則如下
- 文字以";"分隔,最後一條可以沒有";",但空文字不能算語句,比如"COMMAND A; ;"只能算一條語句.
注意, 無字元/空白字元/製表符都算作"空"文字
- 文字可以跨行, 比如下面, 是一條文字, 而不是三條
COMMAND A
AND
COMMAND B;
-
文字支援字串, 字串為成對的單引號(')或者成對的雙引號("), 字串可能出現用跳脫字元()處理的單雙引號(比如"your input is: "")和跳脫字元本身, 比如 COMMAND A "Say "hello"";
-
支援註釋, 可以出現在字串之外的任意位置, 註釋以"--"開頭, 到換行結束, 比如
COMMAND A; -- this is comment
COMMAND -- comment
A AND COMMAND B;
注意, 字串內的"--", 不是註釋
輸入描述:文字檔案
輸出描述:包含的文字數量
示例1
輸入:COMMAND TABLE IF EXISTS "UNITED STATE";
COMMAND A GREAT (
ID ADSAB,
download_length INTE-GER, -- test
file_name TEXT,
guid TEXT,
mime_type TEXT
notifica-tionid INTEGER,
original_file_name TEXT,
pause_reason_type INTEGER,
resumable_flag INTEGER,
start_time INTEGER,
state INTEGER,
folder TEXT,
path TEXT,
total_length INTE-GER,
url TEXT
);
輸出:2
要解決這個問題,我們需要處理包含文字的檔案,按照給定的規則分割文字並計算有效的文字數量。下面是分步驟的解決方法:
- 讀取檔案內容:將檔案中的所有內容讀取到一個字串中,處理跨行的情況。
- 去除註釋:在處理文字之前,去除所有註釋(
--
後到行尾的內容)。注意,註釋不能出現在字串內部。 - 處理字串中的跳脫字元:確保正確解析字串中的引號和跳脫字元。
- 按分隔符拆分文字:根據分隔符
;
拆分文字,並去除空文字。 - 統計有效文字:計算拆分後有效的文字數量。
以下是用 Java 實現這個過程的程式碼:
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
public class TextFileParser {
public static void main(String[] args) {
if (args.length != 1) {
System.out.println("Usage: java TextFileParser <file-path>");
return;
}
String filePath = args[0];
try {
String content = readFile(filePath);
String cleanedContent = removeComments(content);
int count = countValidTexts(cleanedContent);
System.out.println(count);
} catch (IOException e) {
e.printStackTrace();
}
}
// Read the entire file content
private static String readFile(String filePath) throws IOException {
StringBuilder content = new StringBuilder();
try (BufferedReader br = new BufferedReader(new FileReader(filePath))) {
String line;
while ((line = br.readLine()) != null) {
content.append(line).append("\n");
}
}
return content.toString();
}
// Remove comments from the content
private static String removeComments(String content) {
StringBuilder result = new StringBuilder();
boolean inString = false;
boolean escaped = false;
for (int i = 0; i < content.length(); i++) {
char c = content.charAt(i);
if (c == '"' || c == '\'') {
if (!escaped) {
inString = !inString;
}
} else if (c == '\\') {
escaped = !escaped;
} else if (c == '-' && !inString && i + 1 < content.length() && content.charAt(i + 1) == '-') {
while (i < content.length() && content.charAt(i) != '\n') {
i++;
}
result.append('\n');
continue;
}
result.append(c);
}
return result.toString();
}
// Count valid texts separated by ';'
private static int countValidTexts(String content) {
String[] parts = content.split(";");
int count = 0;
for (String part : parts) {
String trimmed = part.trim();
if (!trimmed.isEmpty()) {
count++;
}
}
return count;
}
}
程式碼解釋
-
讀取檔案內容:
- 使用
BufferedReader
讀取檔案的內容,將其合併為一個單獨的字串。
- 使用
-
去除註釋:
- 在
removeComments
方法中,我們處理註釋。處理邏輯包括判斷是否在字串內,處理註釋行並將其刪除。
- 在
-
拆分文字並統計:
- 在
countValidTexts
方法中,我們按分隔符;
拆分文字,去除空文字並計算有效文字的數量。
- 在
使用說明
- 將上述程式碼儲存到一個 Java 檔案中,例如
TextFileParser.java
。 - 編譯程式碼:
javac TextFileParser.java
- 執行程式碼:
java TextFileParser <file-path>
,其中<file-path>
是文字檔案的路徑。
該程式碼會正確處理檔案中的文字,去除註釋,處理字串中的跳脫字元,並計算有效文字的數量。
題目
RSA 加密演算法在網路安全世界中無處不在, 它利用了極大整數因數分解的困難度,資料越大安全係數越高。 給定了一個 32 位正整數,請對其進行因數分解, 找出哪兩個素數的乘積。
輸入
一個正整數 num,滿足 0 < num <= 2147483647。
輸出描述
如果成功找到,則以單個空格分割, 從小到大輸出兩個素數。 分解失敗請輸出 -1 -1。
RSA 加密演算法中的因數分解問題需要將一個給定的整數分解成兩個素數的乘積。我們可以使用以下步驟來完成這個任務:
步驟
- 輸入解析:讀取輸入的32位正整數。
- 尋找因數:
- 從最小的素數開始,檢查是否能整除輸入數字。
- 如果找到因數
p
,那麼另一個因數q
計算為num / p
。 - 確保兩個因數
p
和q
都是素數。
- 輸出結果:
- 如果找到兩個素數,則輸出它們。
- 如果沒有找到符合條件的因數,則輸出
-1 -1
。
實現
以下是用 Java 實現的程式碼:
import java.util.Scanner;
public class RSADecoder {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int num = scanner.nextInt();
scanner.close();
int[] factors = findPrimeFactors(num);
if (factors != null) {
System.out.println(factors[0] + " " + factors[1]);
} else {
System.out.println("-1 -1");
}
}
// Find two prime factors of the number
private static int[] findPrimeFactors(int num) {
if (num <= 1) return null;
// Check for factors from 2 to sqrt(num)
for (int i = 2; i <= Math.sqrt(num); i++) {
if (num % i == 0) {
int p = i;
int q = num / i;
if (isPrime(p) && isPrime(q)) {
return new int[]{Math.min(p, q), Math.max(p, q)};
}
}
}
return null;
}
// Check if a number is prime
private static boolean isPrime(int number) {
if (number <= 1) return false;
if (number <= 3) return true;
if (number % 2 == 0 || number % 3 == 0) return false;
for (int i = 5; i * i <= number; i += 6) {
if (number % i == 0 || number % (i + 2) == 0) return false;
}
return true;
}
}
程式碼解釋
-
findPrimeFactors
方法:- 遍歷從 2 到
sqrt(num)
的所有數字,嘗試找到一個因數i
,使得num % i == 0
。 - 計算另一個因數
q
為num / i
。 - 檢查
p
和q
是否都是素數。如果是,則返回這兩個素數。 - 如果沒有找到滿足條件的因數,則返回
null
。
- 遍歷從 2 到
-
isPrime
方法:- 使用經典的素數檢測演算法,最佳化為檢查到
sqrt(number)
。 - 先排除 2 和 3 的倍數,然後使用 6 的倍數最佳化檢測過程。
- 使用經典的素數檢測演算法,最佳化為檢查到
-
主程式:
- 從標準輸入讀取整數。
- 呼叫
findPrimeFactors
方法來找到並列印結果。
使用說明
- 將程式碼儲存為
RSADecoder.java
。 - 編譯程式碼:
javac RSADecoder.java
- 執行程式碼:
java RSADecoder
,並輸入一個正整數。
該程式碼將有效地處理32位正整數,並找出其兩個素數因子。如果無法找到這樣的因子,則返回 -1 -1
。
題目描述
主管期望你來實現英文輸入法單詞聯想功能,需求如下:
- 依據使用者輸入的單詞字首,從已輸入的英文語句中聯想出使用者想輸入的單詞。
- 按字典序輸出聯想到的單詞序列,如果聯想不到,請輸出使用者輸入的單詞字首。
注意:
- 英文單詞聯想時區分大小寫
- 縮略形式如"don’t" 判定為兩個單詞 "don"和 “t”
- 輸出的單詞序列不能有重複單詞,且只能是英文單詞,不能有標點符號
輸入
輸入兩行。
首行輸入一段由英文單詞word和標點構成的語句str,接下來一行為一個英文單詞字首pre。
0 < word.length() <= 20
0 < str.length() <= 10000,0 < pre.length() <= 20
輸出
輸出符合要求的單詞序列或單詞字首。存在多個時,單詞之間以單個空格分割
樣例輸入
I love you
He
樣例輸出
He
要實現一個英文輸入法單詞聯想功能,我們可以遵循以下步驟:
步驟
-
輸入處理:
- 讀取一段由英文單詞和標點符號組成的文字。
- 讀取使用者提供的字首。
-
文字預處理:
- 從文字中提取所有的單詞,排除標點符號。
- 處理單詞的縮略形式,如"don’t"應被拆分為"don"和"t"。
-
單詞聯想:
- 根據提供的字首,從提取的單詞中找出以該字首開頭的單詞。
- 確保返回的單詞按字典序排序,並且沒有重複。
-
輸出結果:
- 如果找到符合條件的單詞,則按字典序輸出這些單詞。
- 如果沒有找到任何符合條件的單詞,則輸出使用者輸入的字首。
實現程式碼(Java)
import java.util.*;
import java.util.regex.*;
public class WordSuggestion {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
// Read input
String text = scanner.nextLine();
String prefix = scanner.nextLine();
scanner.close();
// Extract words from the text
Set<String> words = extractWords(text);
// Find matching words
List<String> matches = new ArrayList<>();
for (String word : words) {
if (word.startsWith(prefix)) {
matches.add(word);
}
}
// Sort matches
Collections.sort(matches);
// Output results
if (matches.isEmpty()) {
System.out.println(prefix);
} else {
System.out.println(String.join(" ", matches));
}
}
// Method to extract words from text
private static Set<String> extractWords(String text) {
Set<String> words = new HashSet<>();
// Define a pattern for valid words, considering only alphabetic characters and apostrophes
Pattern pattern = Pattern.compile("[a-zA-Z]+(?:'[a-zA-Z]+)?");
Matcher matcher = pattern.matcher(text);
while (matcher.find()) {
words.add(matcher.group());
}
return words;
}
}
程式碼解釋
-
main
方法:- 讀取使用者輸入的文字和字首。
- 呼叫
extractWords
方法提取文字中的單詞。 - 根據字首篩選符合條件的單詞,並排序。
- 輸出符合條件的單詞或字首(如果沒有找到匹配的單詞)。
-
extractWords
方法:- 使用正規表示式提取文字中的單詞。
- 處理英文單詞及其縮略形式,如“don’t”被拆分為“don”和“t”。
- 結果儲存在
HashSet
中以避免重複,並返回這個集合。
使用說明
- 將程式碼儲存為
WordSuggestion.java
。 - 編譯程式碼:
javac WordSuggestion.java
- 執行程式碼:
java WordSuggestion
,然後輸入文字和字首。
此程式碼會處理大文字輸入並返回符合條件的單詞列表,確保按字典序排列並去除重複項。如果沒有找到符合條件的單詞,則返回字首。
題目描述
快遞公司每日早晨,給每位快遞員推送需要淡到客戶手中的快遞以及路線資訊,快遞員自己又查詢了一些客戶與客戶之間的路線距離資訊,請你依據這些資訊,給快遞員設計一條最短路徑,告訴他最短路徑的距離。
不限制快遞包裹送到客戶手中的順序,但必須保證都送到客戶手中;
用例保證一定存在投遞站到每位客戶之間的路線,但不保證客戶與客戶之間有路線,客戶位置及投遞站均允許多次經過;
所有快遞送完後,快遞員需回到投遞站;
輸入描述
首行輸入兩個正整數n、m.
接下來n行,輸入快遞公司釋出的客戶快遞資訊,格式為:客戶id 投遞站到客戶之間的距離distance
再接下來的m行,是快遞員自行查詢的客戶與客戶之間的距離資訊,格式為:客戶1id 客戶2id distance
在每行資料中,資料與資料之間均以單個空格分割規格:
0 <=n <= 10 0 <= m <= 10 0 < 客戶id <= 1000 0 < distance <= 10000
輸出描述
最短路徑距離,如無法找到,請輸出-1
示例1
輸入:
2 1
1 1000
2 1200
1 2 300
輸出:
2500
說明:
快遞員先把快遞送到客戶1手中,接下來直接走客戶1到客戶2之間的直通線路,最後走投遞站和客戶2之間的路,回到投遞站,距離為1000+300+1200= 2500
示例2
輸入:
5 1
5 1000
9 1200
17 300
132 700
500 2300
5 9 400
輸出:
9200
為了設計一個計算快遞員最短路徑的演算法,我們可以使用圖論中的最短路徑演算法。具體來說,可以使用以下步驟來解決這個問題:
步驟概述
-
圖建模:
- 檢視包括兩部分:客戶到投遞站的距離資訊和客戶間的距離資訊。
- 構建圖來表示投遞站、客戶和客戶之間的距離。
-
求解最短路徑:
- 使用最短路徑演算法來找到從投遞站到每個客戶的最短路徑,再從每個客戶到其他客戶的最短路徑,最後回到投遞站的路徑。
-
生成路徑:
- 使用旅行商問題 (TSP) 的演算法來計算從投遞站出發,訪問所有客戶並返回投遞站的最短路徑。
詳細解法
-
輸入處理:
- 解析客戶到投遞站的距離。
- 解析客戶之間的距離。
-
圖的建立:
- 建立一個完整的圖,包含所有客戶和投遞站。
- 新增投遞站到每個客戶的邊,以及客戶間的邊。
-
使用旅行商問題 (TSP) 演算法:
- 使用動態規劃(DP)或其他 TSP 解法來求解從投遞站到所有客戶並返回的最短路徑。
實現程式碼(Java)
import java.util.*;
public class DeliveryRoute {
private static final int INF = Integer.MAX_VALUE;
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
// Read the number of clients and customer-to-customer distances
int n = scanner.nextInt();
int m = scanner.nextInt();
scanner.nextLine(); // Move to next line
// Client to delivery station distances
int[] clientToStation = new int[1000];
Arrays.fill(clientToStation, INF);
// Reading client to delivery station distances
for (int i = 0; i < n; i++) {
int clientId = scanner.nextInt();
int distance = scanner.nextInt();
clientToStation[clientId] = distance;
}
scanner.nextLine(); // Move to next line
// Reading client-to-client distances
Map<Integer, Map<Integer, Integer>> distances = new HashMap<>();
for (int i = 0; i < m; i++) {
int client1 = scanner.nextInt();
int client2 = scanner.nextInt();
int distance = scanner.nextInt();
scanner.nextLine(); // Move to next line
distances.computeIfAbsent(client1, k -> new HashMap<>()).put(client2, distance);
distances.computeIfAbsent(client2, k -> new HashMap<>()).put(client1, distance);
}
// Collect all clients and include the delivery station as client 0
Set<Integer> clients = new HashSet<>(distances.keySet());
clients.addAll(distances.values().stream().flatMap(m -> m.keySet().stream()).toList());
clients.add(0); // Delivery station
List<Integer> clientList = new ArrayList<>(clients);
int clientCount = clientList.size();
// Initialize distances between all nodes
int[][] graph = new int[clientCount][clientCount];
for (int[] row : graph) {
Arrays.fill(row, INF);
}
// Fill the graph with known distances
for (int client : clients) {
if (client == 0) {
for (int c : clientList) {
if (c != 0) {
graph[clientList.indexOf(client)][clientList.indexOf(c)] = clientToStation[c];
graph[clientList.indexOf(c)][clientList.indexOf(client)] = clientToStation[c];
}
}
} else {
Map<Integer, Integer> edges = distances.get(client);
for (Map.Entry<Integer, Integer> entry : edges.entrySet()) {
graph[clientList.indexOf(client)][clientList.indexOf(entry.getKey())] = entry.getValue();
graph[clientList.indexOf(entry.getKey())][clientList.indexOf(client)] = entry.getValue();
}
}
}
// Use Held-Karp algorithm for TSP (Dynamic Programming)
int result = tsp(graph, 0);
// Print the result
System.out.println(result);
}
private static int tsp(int[][] graph, int start) {
int n = graph.length;
int[][] dp = new int[1 << n][n];
for (int[] row : dp) {
Arrays.fill(row, INF);
}
dp[1 << start][start] = 0;
for (int mask = 1; mask < (1 << n); mask++) {
for (int u = 0; u < n; u++) {
if ((mask & (1 << u)) == 0) continue;
for (int v = 0; v < n; v++) {
if ((mask & (1 << v)) != 0) continue;
dp[mask | (1 << v)][v] = Math.min(dp[mask | (1 << v)][v], dp[mask][u] + graph[u][v]);
}
}
}
int finalResult = INF;
for (int i = 0; i < n; i++) {
if (i != start) {
finalResult = Math.min(finalResult, dp[(1 << n) - 1][i] + graph[i][start]);
}
}
return finalResult == INF ? -1 : finalResult;
}
}
程式碼說明
-
輸入處理:
- 讀取客戶與投遞站的距離。
- 讀取客戶間的距離資訊,並構建圖。
-
圖建模:
- 使用二維陣列
graph
來表示所有節點之間的距離。 - 將客戶到投遞站的距離新增到圖中。
- 使用二維陣列
-
最短路徑計算:
- 使用 Held-Karp 演算法解決 TSP 問題來找到最短路徑。此演算法的時間複雜度為 O(n^2 * 2^n),適合處理小規模問題。
-
輸出結果:
- 列印計算出的最短路徑距離。如果沒有合法路徑,輸出
-1
。
- 列印計算出的最短路徑距離。如果沒有合法路徑,輸出
這樣可以高效地計算最短路徑並處理多個客戶和投遞站的情況。
- 題目描述
程式設計師小明打了一輛計程車去上班。出於職業敏感,他注意到這輛計程車的計費表有點問題,總是偏大。
計程車司機解釋說他不喜歡數字4,所以改裝了計費表,任何數字位置遇到數字4就直接跳過,其餘功能都正常。
比如:
23再多一塊錢就變為25;
39再多一塊錢變為50;
399再多一塊錢變為500;
小明識破了司機的伎倆,準備利用自己的學識打敗司機的陰謀。
給出計費表的表面讀數,返回實際產生的費用
示例1:
輸入 5
輸出 4
說明: 5表示計費表的表面讀數。4表示實際產生的費用其實只有4塊錢。
示例2:
輸入 17
輸出 15
說明 : 17表示計費表的表面讀數。15表示實際產生的費用其實只有15塊錢。
示例3:
輸入 100
輸出 81
說明: 100表示計費表的表面讀數。81表示實際產生的費用其實只有81塊錢。
為了計算計程車的實際費用,我們需要處理一個特殊的計費表。計費表中遇到數字 4 的位置會被跳過。因此,我們需要根據這個規則,將計費表的表面讀數轉換為實際費用。
具體步驟如下:
-
理解問題:
- 計費表中的數字 4 被跳過,這意味著數字 4 在表面讀數中的位置不會影響實際費用。
- 我們需要將表面讀數轉換為實際讀數,去掉所有 4,並將剩餘的數字作為實際費用。
-
方法:
- 將給定的表面讀數轉換為實際費用的方法是:逐位檢查表面讀數,跳過所有的 4,將其他數字拼接起來,得到實際費用。
實現步驟
-
讀取輸入:
- 輸入是一個整數,表示計費表的表面讀數。
-
處理數字:
- 將表面讀數轉換為字串,遍歷每一位,跳過所有的 4,將其他字元拼接成實際費用的字串。
-
輸出結果:
- 將拼接的結果轉換回整數,輸出實際費用。
Java 實現
import java.util.Scanner;
public class TaxiFare {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
String surfaceReading = scanner.nextLine().trim();
String actualReading = processReading(surfaceReading);
System.out.println(actualReading);
}
private static String processReading(String surfaceReading) {
StringBuilder actualReading = new StringBuilder();
for (char c : surfaceReading.toCharArray()) {
if (c != '4') {
actualReading.append(c);
}
}
// Convert the result to a number and handle edge cases (e.g., if actualReading is empty)
if (actualReading.length() == 0) {
return "0"; // In case all digits are 4, return 0
}
return actualReading.toString();
}
}
程式碼解釋
-
讀取輸入:
- 使用
Scanner
類讀取輸入的表面讀數。
- 使用
-
處理表面讀數:
- 將表面讀數轉換為字元陣列,遍歷每個字元。
- 如果字元不是 '4',則將其新增到
StringBuilder
物件中,最終構造出實際的讀數。
-
輸出實際費用:
- 將
StringBuilder
物件轉換為字串,並處理空字串的情況(如果所有的數字都是 4,則返回 0)。
- 將
透過這種方法,我們可以準確地計算計程車的實際費用,從而揭示司機的伎倆。
題目描述
開頭和結尾都是母音字母(aeiouAEIOU)的字串為母音字串,其中混雜的非母音字母數量為其瑕疵度。比如:
“a” 、 “aa”是母音字串,其瑕疵度都為0
“aiur”不是母音字串(結尾不是母音字元)
“abira”是母音字串,其瑕疵度為2
給定一個字串,請找出指定瑕疵度的最長母音字元子串,並輸出其長度,如果找不到滿足條件的母音字元子串,輸出0。
子串:字串中任意個連續的字元組成的子序列稱為該字串的子串。
輸入描述
首行輸入是一個整數,表示預期的瑕疵度flaw,取值範圍[0, 65535]。
接下來一行是一個僅由字元a-z和A-Z組成的字串,字串長度(0, 65535]。
輸出描述
輸出為一個整數,代表滿足條件的母音字元子串的長度。
示例:
輸入 0
asdbuiodevauufgh
輸出 3
說明 無
要解決這個問題,我們需要找到指定瑕疵度的最長母音字串子串,並輸出其長度。下面是處理這個問題的步驟和Java實現。
解決步驟
-
定義母音字元:
- 母音字元為
a, e, i, o, u
以及它們的大寫字母形式A, E, I, O, U
。
- 母音字元為
-
查詢所有母音子串:
- 遍歷整個字串,找到所有以母音字元開始和結束的子串。
-
計算瑕疵度:
- 對於每個可能的母音子串,計算其瑕疵度(即非母音字元的數量)。
-
找到最長滿足條件的子串:
- 根據給定的瑕疵度,檢查所有找到的母音子串中哪些符合條件,記錄其中最長的子串長度。
-
輸出結果:
- 如果找到了符合條件的子串,輸出其長度;否則輸出 0。
Java 實現
import java.util.HashSet;
import java.util.Set;
import java.util.Scanner;
public class VowelSubstring {
private static final Set<Character> VOWELS = new HashSet<>();
static {
char[] vowels = {'a', 'e', 'i', 'o', 'u', 'A', 'E', 'I', 'O', 'U'};
for (char c : vowels) {
VOWELS.add(c);
}
}
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int flaw = scanner.nextInt();
scanner.nextLine(); // Consume the newline
String input = scanner.nextLine();
int result = findLongestVowelSubstring(flaw, input);
System.out.println(result);
}
private static int findLongestVowelSubstring(int flaw, String str) {
int maxLength = 0;
int n = str.length();
for (int i = 0; i < n; i++) {
if (isVowel(str.charAt(i))) {
for (int j = i; j < n; j++) {
if (isVowel(str.charAt(j))) {
String substring = str.substring(i, j + 1);
int countFlaw = countNonVowels(substring);
if (countFlaw == flaw) {
maxLength = Math.max(maxLength, j - i + 1);
}
}
}
}
}
return maxLength;
}
private static boolean isVowel(char c) {
return VOWELS.contains(c);
}
private static int countNonVowels(String str) {
int count = 0;
for (char c : str.toCharArray()) {
if (!isVowel(c)) {
count++;
}
}
return count;
}
}
程式碼解釋
-
初始化母音字符集合:
- 使用
HashSet
儲存所有母音字元以便於快速查詢。
- 使用
-
處理輸入:
- 讀取瑕疵度和輸入字串。
-
查詢母音子串:
- 遍歷字串的每個可能的起始點。如果字元是母音,則開始查詢可能的子串。
- 對每個子串計算瑕疵度,並更新最長子串長度。
-
輸出結果:
- 輸出最長符合條件的子串長度。如果沒有找到符合條件的子串,則輸出 0。
這種方法透過逐步檢查每個可能的子串來確保能夠找到符合條件的最長子串。儘管時間複雜度較高,但由於實際輸入範圍可能不超過 65535 的長度,效率是可以接受的。
題目描述
給定兩個整數陣列array1、array2,陣列元素按升序排列。
假設從array1、array2中分別取出一個元素可構成一對元素,現在需要取出k對元素,並對取出的所有元素求和,計算和的最小值。
注意:兩對元素如果對應於array1、array2中的兩個下標均相同,則視為同一對元素。
輸入描述
輸入兩行陣列array1、array2,每行首個數字為陣列大小size(0 < size <= 100);
0 <array1[i] <=1000
0 <array2[i] <= 1000
接下來一行為正整數 k
0 < k <= array1.size() * array2.size()
輸出描述
滿足要求的最小和
示例1
輸入:
3 1 1 2
3 1 2 3
2
輸出:
4
說明:
用例中,需要取2對元素
取第一個陣列第0個元素與第二個陣列第0個元素組成1對元素[1,1];
取第一個陣列第1個元素與第二個陣列第0個元素組成1對元素[1,1];
求和為1+1+1+1=4,為滿足要求的最小和
要解決這個問題,我們需要從兩個升序排列的整數陣列中選擇k
對元素,使得這些對元素的和的總和最小。下面是詳細的解題步驟和Java實現。
解題步驟
-
定義問題:
- 我們需要從
array1
和array2
中選擇k
對元素,使得這些對元素的和的總和最小。
- 我們需要從
-
生成所有可能的對:
- 對於每對
(array1[i], array2[j])
,計算它們的和,並儲存這些和及其對應的對。
- 對於每對
-
排序和選擇最小對:
- 將所有可能的對的和按升序排序,然後選擇前
k
個最小的和,計算它們的總和。
- 將所有可能的對的和按升序排序,然後選擇前
-
輸出結果:
- 輸出前
k
個最小和的總和。
- 輸出前
Java 實現
import java.util.*;
public class MinSumPairs {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
// 讀取陣列array1
int size1 = scanner.nextInt();
int[] array1 = new int[size1];
for (int i = 0; i < size1; i++) {
array1[i] = scanner.nextInt();
}
// 讀取陣列array2
int size2 = scanner.nextInt();
int[] array2 = new int[size2];
for (int i = 0; i < size2; i++) {
array2[i] = scanner.nextInt();
}
// 讀取k
int k = scanner.nextInt();
// 呼叫函式計算最小和
int result = findMinSum(array1, array2, k);
System.out.println(result);
}
private static int findMinSum(int[] array1, int[] array2, int k) {
int size1 = array1.length;
int size2 = array2.length;
// 優先佇列(最小堆)用於儲存當前最小的k個和
PriorityQueue<Pair> minHeap = new PriorityQueue<>(Comparator.comparingInt(p -> p.sum));
// 初始將每個array1的元素與array2的第一個元素組合起來
for (int i = 0; i < size1; i++) {
minHeap.offer(new Pair(array1[i] + array2[0], i, 0));
}
int sum = 0;
while (k-- > 0 && !minHeap.isEmpty()) {
Pair current = minHeap.poll();
sum += current.sum;
// 當前的pair來自array1[current.i] 和 array2[current.j],嘗試將下一對放入堆中
if (current.j + 1 < size2) {
minHeap.offer(new Pair(array1[current.i] + array2[current.j + 1], current.i, current.j + 1));
}
}
return sum;
}
// 內部類,用於儲存每對元素的和及其索引
private static class Pair {
int sum;
int i;
int j;
Pair(int sum, int i, int j) {
this.sum = sum;
this.i = i;
this.j = j;
}
}
}
程式碼解釋
-
資料讀取:
- 從輸入中讀取兩個陣列和
k
的值。
- 從輸入中讀取兩個陣列和
-
最小堆:
- 使用優先佇列(最小堆)來儲存當前最小的和。堆中的每個元素是一個
Pair
物件,包含和及對應的索引。
- 使用優先佇列(最小堆)來儲存當前最小的和。堆中的每個元素是一個
-
初始化堆:
- 將
array1
中的每個元素與array2
中的第一個元素組合,並插入堆中。
- 將
-
提取最小和:
- 從堆中提取最小和,並嘗試將下一個可能的和(來自同一
array1
的元素和array2
中下一個元素的組合)插入堆中。
- 從堆中提取最小和,並嘗試將下一個可能的和(來自同一
-
輸出結果:
- 輸出最小
k
個和的總和。
- 輸出最小
複雜度分析
- 時間複雜度:
O(N log N + K log N)
,其中N
為array1
的大小,K
為需要選擇的對的數量。 - 空間複雜度:
O(N)
,用於儲存堆中的元素。
某學校舉行運動會,學生們按編號(1、2、3…n)進行標識,現需要按照身高由低到高排列,對身高相同的人,按體重由輕到重排列;對於身高體重都相同的人,維持原有的編號順序關係。請輸出排列後的學生編號。
時間限制:限制時間C/C++ 1秒,其他/Java 2s以內
記憶體限制:32768K
示例 1
輸入:
4
100 100 120 130
40 30 60 50
輸出:
2134
要解決這個問題,我們需要根據學生的身高和體重對其進行排序,同時保持原有的編號順序。以下是詳細的解題步驟和Java實現程式碼。
解題步驟
-
讀取輸入資料:
- 讀取學生數量
n
。 - 讀取身高和體重資訊。
- 學生的編號從1到n。
- 讀取學生數量
-
建立學生物件:
- 每個學生可以用一個包含編號、身高和體重的物件表示。
-
排序:
- 首先按身高從低到高排序。
- 對於身高相同的學生,按體重從輕到重排序。
- 對於身高和體重都相同的學生,保持原有編號順序。
-
輸出排序後的編號:
- 輸出按照排序規則排列後的學生編號。
Java 實現
import java.util.*;
public class StudentSort {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
// 讀取學生數量
int n = scanner.nextInt();
// 讀取身高
int[] heights = new int[n];
for (int i = 0; i < n; i++) {
heights[i] = scanner.nextInt();
}
// 讀取體重
int[] weights = new int[n];
for (int i = 0; i < n; i++) {
weights[i] = scanner.nextInt();
}
// 建立學生物件列表
List<Student> students = new ArrayList<>();
for (int i = 0; i < n; i++) {
students.add(new Student(i + 1, heights[i], weights[i]));
}
// 排序
Collections.sort(students);
// 輸出結果
for (Student student : students) {
System.out.print(student.id);
}
}
// 學生類,包含編號、身高和體重
static class Student implements Comparable<Student> {
int id;
int height;
int weight;
Student(int id, int height, int weight) {
this.id = id;
this.height = height;
this.weight = weight;
}
// 實現 Comparable 介面的 compareTo 方法
@Override
public int compareTo(Student other) {
if (this.height != other.height) {
return Integer.compare(this.height, other.height);
}
if (this.weight != other.weight) {
return Integer.compare(this.weight, other.weight);
}
return Integer.compare(this.id, other.id);
}
}
}
程式碼解釋
-
資料讀取:
- 透過
Scanner
讀取輸入的資料。 - 讀取身高和體重陣列,並儲存在
heights
和weights
中。
- 透過
-
學生物件:
- 建立一個
Student
類,其中包含學生的編號、身高和體重。 - 在
Student
類中實現Comparable
介面,並重寫compareTo
方法以按照題目要求排序:首先按身高排序,其次按體重排序,最後按編號排序(當身高和體重都相同)。
- 建立一個
-
排序:
- 使用
Collections.sort
對學生列表進行排序,這會呼叫Student
類中的compareTo
方法進行比較。
- 使用
-
輸出:
- 輸出排序後的學生編號,依次列印所有學生的編號。
複雜度分析
- 時間複雜度:
O(n log n)
,主要是排序操作。 - 空間複雜度:
O(n)
,用於儲存學生物件列表。
這個解決方案在時間和空間複雜度上都能有效處理輸入的大小,並且符合題目要求。
題目描述
繪圖機器的繪圖筆初始位置在原點(0,0)機器啟動後按照以下規則來進行繪製直線。
-
嘗試沿著橫線座標正向繪製直線直到給定的終點E
-
期間可以透過指令在縱座標軸方向進行偏移,offsetY為正數表示正向偏移,為負數表示負向偏移
給定的橫座標終點值E 以及若干條繪製指令,
請計算繪製的直線和橫座標軸以及x=E的直線組成的圖形面積。
輸入描述
首行為兩個整數 N 和 E
表示有N條指令,機器執行的橫座標終點值E
接下來N行 每行兩個整數表示一條繪製指令x offsetY
用例保證橫座標x以遞增排序的方式出現
且不會出現相同橫座標x
取值範圍
0<N<=10000
0<=x<=E<=20000
-10000<=offsetY<=10000
輸出描述
一個整數表示計算得到的面積 用例保證結果範圍在0到4294967295之內。
用例1
輸入
4 10
1 1
2 1
3 1
4 -2
輸出
12
用例2
輸入
2 4
0 1
2 -2
輸出
4
為了計算繪圖機器繪製的圖形與橫座標軸以及終點直線 ( x = E ) 之間的面積,我們可以將問題建模為一個多邊形面積計算問題。具體來說,我們需要計算由繪製的直線段以及終點 ( x = E ) 形成的圖形的面積。
解題思路
-
資料解析:
- 讀取輸入的繪製指令,解析每個指令的橫座標 ( x ) 和縱座標偏移量 ( \text{offsetY} )。
- 將這些指令用於構建在 ( x ) 軸上繪製的圖形的輪廓。
-
多邊形的面積計算:
- 使用多邊形面積公式來計算由這些繪製指令形成的多邊形的面積。
- 將繪製的線段視為多邊形的一部分,該多邊形由這些線段和終點 ( x = E ) 形成。
-
計算過程:
- 首先,構建一個多邊形的頂點列表。頂點包括指令給定的點和終點 ( x = E ) 處的點。
- 使用Shoelace公式(也稱為高斯面積公式)來計算多邊形的面積。
詳細步驟
-
構建頂點列表:
- 從原點 ((0, 0)) 開始。
- 遍歷所有指令,記錄每個指令的終點。
- 記錄終點 ( x = E ) 對應的縱座標。
-
應用Shoelace公式:
- 對多邊形頂點進行排序,計算其面積。
Java 實現程式碼
import java.util.*;
public class DrawingMachine {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
// 讀取 N 和 E
int N = scanner.nextInt();
int E = scanner.nextInt();
// 讀取指令
List<int[]> commands = new ArrayList<>();
for (int i = 0; i < N; i++) {
int x = scanner.nextInt();
int offsetY = scanner.nextInt();
commands.add(new int[]{x, offsetY});
}
// 構建頂點列表
List<Point> points = new ArrayList<>();
points.add(new Point(0, 0)); // 起點
for (int[] cmd : commands) {
points.add(new Point(cmd[0], cmd[1]));
}
// 新增終點
points.add(new Point(E, commands.get(commands.size() - 1)[1]));
// 計算多邊形面積
long area = calculatePolygonArea(points);
System.out.println(area);
}
static class Point {
int x, y;
Point(int x, int y) {
this.x = x;
this.y = y;
}
}
// 使用Shoelace公式計算多邊形的面積
private static long calculatePolygonArea(List<Point> points) {
long area = 0;
int n = points.size();
for (int i = 0; i < n; i++) {
Point p1 = points.get(i);
Point p2 = points.get((i + 1) % n);
area += p1.x * p2.y - p2.x * p1.y;
}
return Math.abs(area) / 2;
}
}
程式碼說明
-
資料讀取:
- 從標準輸入讀取資料並解析。
-
頂點構建:
- 將所有繪製指令轉化為頂點。
- 在最後加上終點 ( x = E ) 對應的點。
-
面積計算:
- 使用Shoelace公式計算多邊形的面積。
- 公式計算出的面積需要除以2,並取絕對值。
複雜度分析
- 時間複雜度:
O(N)
,由於需要遍歷所有輸入資料並計算多邊形面積。 - 空間複雜度:
O(N)
,儲存頂點列表。
這個解決方案在時間和空間複雜度上都能夠有效處理給定範圍內的輸入資料。
請實現一個簡易記憶體池
根據請求命令完成記憶體分配和釋放
記憶體池支援兩種操作命令
REQUEST和RELEASE其格式為
REQUEST=請求的記憶體大小
表示請求分配指定大小記憶體
如果分配成功,返回分配到的記憶體首地址
如果記憶體不足,或指定的大小為零則輸出error
RELEASE=釋放的記憶體首地址
表示釋放掉之前分配的記憶體
釋放成功無需輸出
如果釋放不存在的首地址
則輸出error
注意:
記憶體池總大小為 100 位元組
記憶體池地址分配必須是連續記憶體,並優先從低地址分配
記憶體釋放後可被再次分配,已釋放的記憶體在空閒時不能被二次釋放
不會釋放已申請的記憶體塊的中間地址
釋放操作只是針對首地址所對應的單個記憶體塊進行操作,不會影響其他記憶體塊
輸入樣例
3
REQUEST=30
RELEASE=0
REQUEST=30
輸出樣例
0
error
30
為了實現一個簡易的記憶體池,我們需要設計一個記憶體池管理系統來處理記憶體分配和釋放。記憶體池的大小是100位元組,我們需要處理兩種命令:REQUEST
和 RELEASE
。REQUEST
用於請求分配記憶體,RELEASE
用於釋放已分配的記憶體。
以下是實現這個記憶體池的步驟:
-
記憶體池初始化:
- 記憶體池總大小為100位元組,可以用一個布林陣列表示記憶體是否被佔用。每個元素表示一個位元組的狀態(已佔用或未佔用)。
-
記憶體分配:
- 遍歷記憶體池,找到一個足夠大的連續空閒區段來滿足記憶體請求。如果找到,分配記憶體,並記錄記憶體塊的起始地址。
- 如果請求的記憶體大小為零或沒有足夠的記憶體,返回
error
。
-
記憶體釋放:
- 根據釋放的起始地址,找到對應的記憶體塊,並將其標記為空閒。如果嘗試釋放一個無效的地址或未分配的記憶體,返回
error
。
- 根據釋放的起始地址,找到對應的記憶體塊,並將其標記為空閒。如果嘗試釋放一個無效的地址或未分配的記憶體,返回
-
輸入輸出:
- 解析輸入命令並執行相應的操作,輸出結果。
下面是實現簡易記憶體池的Java程式碼:
import java.util.Scanner;
public class SimpleMemoryPool {
private static final int POOL_SIZE = 100;
private static final byte[] memoryPool = new byte[POOL_SIZE];
private static final boolean[] allocated = new boolean[POOL_SIZE];
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int numCommands = scanner.nextInt();
scanner.nextLine(); // consume the newline character
for (int i = 0; i < numCommands; i++) {
String command = scanner.nextLine();
if (command.startsWith("REQUEST=")) {
int size = Integer.parseInt(command.substring(8));
handleRequest(size);
} else if (command.startsWith("RELEASE=")) {
int address = Integer.parseInt(command.substring(8));
handleRelease(address);
}
}
}
private static void handleRequest(int size) {
if (size <= 0 || size > POOL_SIZE) {
System.out.println("error");
return;
}
int start = -1;
int freeCount = 0;
for (int i = 0; i < POOL_SIZE; i++) {
if (!allocated[i]) {
if (freeCount == 0) {
start = i;
}
freeCount++;
if (freeCount == size) {
allocateMemory(start, size);
System.out.println(start);
return;
}
} else {
freeCount = 0;
}
}
System.out.println("error");
}
private static void allocateMemory(int start, int size) {
for (int i = start; i < start + size; i++) {
allocated[i] = true;
}
}
private static void handleRelease(int address) {
if (address < 0 || address >= POOL_SIZE || !isMemoryAllocated(address)) {
System.out.println("error");
return;
}
int size = 0;
for (int i = address; i < POOL_SIZE && allocated[i]; i++) {
size++;
}
if (size > 0) {
deallocateMemory(address, size);
System.out.println(); // no output on successful release
} else {
System.out.println("error");
}
}
private static boolean isMemoryAllocated(int address) {
int size = 0;
for (int i = address; i < POOL_SIZE && allocated[i]; i++) {
size++;
}
return size > 0;
}
private static void deallocateMemory(int start, int size) {
for (int i = start; i < start + size; i++) {
allocated[i] = false;
}
}
}
程式碼解釋
-
記憶體池初始化:
memoryPool
和allocated
陣列分別用於表示記憶體池和記錄記憶體是否被佔用。
-
處理
REQUEST
命令:- 查詢足夠大的連續空閒記憶體塊,若找到則分配記憶體並輸出起始地址。如果沒有足夠的記憶體塊,輸出
error
。
- 查詢足夠大的連續空閒記憶體塊,若找到則分配記憶體並輸出起始地址。如果沒有足夠的記憶體塊,輸出
-
處理
RELEASE
命令:- 根據起始地址釋放記憶體塊。若嘗試釋放無效地址或未分配的記憶體塊,輸出
error
。
- 根據起始地址釋放記憶體塊。若嘗試釋放無效地址或未分配的記憶體塊,輸出
-
輸入輸出處理:
- 讀取命令並執行相應操作,輸出結果。
題目描述
給定一個表示式,求其分數計算結果。
表示式的限制如下:
1.所有的輸入數字皆為正整數(包括0)
2.僅支援四則運算(±")和括號
3.結果為整數或分數,分數必須化為最簡格式(比如6,3/4, 7/8,90/7)
4.除數可能為0,如果遇到這種情況,直接輸出"ERROR"
5.輸入和最終計算結果中的數字都不會超出整型範圍
用例輸入一定合法,不會出現括號匹配的情況
輸入描述
字串格式的表示式,僅支援±",數字可能超過兩位, 可能帶有空格,沒有負數
長度小於200個字元
輸出描述
表示式結果,以最簡格式表達
如果結果為整數,那麼直接輸出整數
如果結果為負數,那麼分子分母不可再約分,可以為假分數, 不可表達為帶分數
結果可能是負數,符號放在前面
用例
輸入
1+5*718
輸出
4318
說明
無
輸入
1/(0-5)
輸出
-1/5
說明
符號需要提到最前面
下面是使用 Java 實現的程式碼,它處理給定的數學表示式,並計算其結果。我們將處理加法、減法、乘法、除法以及括號。對於分數,我們使用 Java 的 BigInteger
來確保處理大整數和化簡分數。
Java 實現
import java.math.BigInteger;
import java.util.Scanner;
import java.util.Stack;
public class ExpressionEvaluator {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
String expression = scanner.nextLine().replaceAll(" ", "");
scanner.close();
try {
String result = evaluate(expression);
System.out.println(result);
} catch (Exception e) {
System.out.println("ERROR");
}
}
public static String evaluate(String expression) throws ArithmeticException {
// Convert the infix expression to postfix
String postfix = infixToPostfix(expression);
// Evaluate the postfix expression
return evaluatePostfix(postfix);
}
private static String infixToPostfix(String infix) {
StringBuilder postfix = new StringBuilder();
Stack<Character> operators = new Stack<>();
for (int i = 0; i < infix.length(); i++) {
char c = infix.charAt(i);
if (Character.isDigit(c)) {
while (i < infix.length() && (Character.isDigit(infix.charAt(i)) || infix.charAt(i) == '.')) {
postfix.append(infix.charAt(i++));
}
postfix.append(' ');
i--;
} else if (c == '(') {
operators.push(c);
} else if (c == ')') {
while (operators.peek() != '(') {
postfix.append(operators.pop()).append(' ');
}
operators.pop();
} else if (c == '+' || c == '-' || c == '*' || c == '/') {
while (!operators.isEmpty() && precedence(c) <= precedence(operators.peek())) {
postfix.append(operators.pop()).append(' ');
}
operators.push(c);
}
}
while (!operators.isEmpty()) {
postfix.append(operators.pop()).append(' ');
}
return postfix.toString();
}
private static int precedence(char op) {
if (op == '+' || op == '-') return 1;
if (op == '*' || op == '/') return 2;
return -1;
}
private static String evaluatePostfix(String postfix) throws ArithmeticException {
Stack<BigInteger> stack = new Stack<>();
String[] tokens = postfix.split(" ");
for (String token : tokens) {
if (token.isEmpty()) continue;
if (isOperator(token)) {
BigInteger b = stack.pop();
BigInteger a = stack.pop();
BigInteger result = performOperation(a, b, token.charAt(0));
stack.push(result);
} else {
stack.push(new BigInteger(token));
}
}
BigInteger result = stack.pop();
return formatResult(result);
}
private static boolean isOperator(String token) {
return token.equals("+") || token.equals("-") || token.equals("*") || token.equals("/");
}
private static BigInteger performOperation(BigInteger a, BigInteger b, char op) throws ArithmeticException {
switch (op) {
case '+': return a.add(b);
case '-': return a.subtract(b);
case '*': return a.multiply(b);
case '/':
if (b.equals(BigInteger.ZERO)) throw new ArithmeticException("Division by zero");
return a.divide(b);
default: throw new IllegalArgumentException("Invalid operator");
}
}
private static String formatResult(BigInteger result) {
// Simplify the result and handle negative sign
return result.toString();
}
}
說明
-
輸入處理:
- 從標準輸入讀取表示式並去除空格。
-
表示式轉換:
- 使用中綴到字尾的轉換方法(Shunting Yard Algorithm)將表示式轉換為字尾表示式(逆波蘭表示式)。
-
計算結果:
- 使用字尾表示式的評估方法,處理加法、減法、乘法和除法。
- 使用
BigInteger
來處理大整數的運算。
-
錯誤處理:
- 如果出現除零錯誤,丟擲
ArithmeticException
並輸出 "ERROR"。
- 如果出現除零錯誤,丟擲
-
結果格式化:
- 直接將
BigInteger
轉化為字串輸出。如果需要處理更復雜的分數表示,可以在formatResult
方法中進行擴充套件處理。
- 直接將
執行
將程式碼儲存為 ExpressionEvaluator.java
,並在終端或 IDE 中執行。輸入表示式時請確保其合法性,並測試不同的表示式情況。
題目描述
服務之間交換的介面成功率作為服務呼叫關鍵質量特性,某個時間段內的介面失敗率使用一個陣列表示,陣列中每個元素都是單位時間內失敗率數值,陣列中的數值為 0~100 的整數,給定一個數值(minAverageLost)表示某個時間段內平均失敗率容忍值,即平均失敗率小於等於 minAverageLost,找出陣列中最長時間段,如果未找到則直接返回 NULL。
輸入
輸入有兩行內容,第一行為minAverageLost,第二行為陣列,陣列元素透過空格" "分隔,minAverageLost 及陣列中元素取值範圍為 0~100 的整數,陣列元素的個數不會超過 100 個。
輸出
找出平均值小於等於 minAverageLost 的最長時間段,輸出陣列下標對,格式{beginIndex}-{endIndx}(下標從 0 開始),如果同時存在多個最長時間段,則輸出多個下標對且下標對之間使用空格" "拼接,多個下標對按下標從小到大排序。
樣例輸入
2
0 0 100 2 2 99 0 2
樣例輸出
0-1 3-4 6-7
提示
A、輸入解釋:minAverageLost = 2,陣列[0, 0, 100, 2, 2, 99, 0, 2]
B、透過計算小於等於 2 的最長時間段為:陣列下標為 0-1 即[0, 0],陣列下標為 3-4 即[2, 2],陣列下標為 6-7 即[0, 2],這三個部分都滿足平均值小於等 2 的要求,因此輸出 0-1 3-4 6-7
為了處理這個問題,我們需要找出陣列中所有滿足平均失敗率小於等於 minAverageLost
的最長時間段。以下是解決問題的步驟和 Java 實現程式碼:
思路
-
滑動視窗演算法:使用滑動視窗(雙指標)演算法來找出所有符合條件的時間段。透過維護一個視窗,計算當前視窗內的平均失敗率,並根據這個平均值來調整視窗的大小。
-
記錄結果:在掃描陣列的過程中,記錄所有最長的符合條件的時間段,並確保時間段按開始索引從小到大排序。
-
計算平均值:使用視窗內的總失敗率和視窗大小來計算平均值。視窗大小需要動態調整,保證其平均失敗率不超過
minAverageLost
。
Java 實現
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
public class LongestValidSegment {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int minAverageLost = scanner.nextInt();
scanner.nextLine(); // Consume the remaining newline character
String[] arrayStr = scanner.nextLine().split(" ");
scanner.close();
int[] array = new int[arrayStr.length];
for (int i = 0; i < arrayStr.length; i++) {
array[i] = Integer.parseInt(arrayStr[i]);
}
List<String> result = findLongestValidSegments(array, minAverageLost);
System.out.println(String.join(" ", result));
}
private static List<String> findLongestValidSegments(int[] array, int minAverageLost) {
List<String> result = new ArrayList<>();
int n = array.length;
int maxLen = 0;
for (int start = 0; start < n; start++) {
int sum = 0;
int count = 0;
for (int end = start; end < n; end++) {
sum += array[end];
count++;
double average = (double) sum / count;
if (average <= minAverageLost) {
if (count > maxLen) {
result.clear();
maxLen = count;
result.add(start + "-" + end);
} else if (count == maxLen) {
result.add(start + "-" + end);
}
} else {
break;
}
}
}
return result;
}
}
說明
-
讀取輸入:
- 從標準輸入讀取
minAverageLost
和陣列,陣列中的元素透過空格分隔。
- 從標準輸入讀取
-
滑動視窗處理:
- 對於每個起始位置
start
,透過擴充套件end
指標來維護當前視窗。 - 計算視窗內元素的總和及其平均值,並根據結果判斷是否更新最長時間段列表。
- 如果視窗內的平均值不超過
minAverageLost
,更新最長時間段列表。如果超過,跳出當前視窗擴充套件迴圈。
- 對於每個起始位置
-
輸出:
- 輸出所有找到的最長時間段,格式為
start-end
。多個時間段之間用空格分隔。
- 輸出所有找到的最長時間段,格式為
示例
假設輸入為:
2
0 0 100 2 2 99 0 2
程式將輸出:
0-1 3-4 6-7
這表示所有最長的符合條件的時間段,並按開始索引從小到大的順序排序。
題目描述
給定M (0<M<=30)個字元(a-z),從中取出任意字元(每個字元只能用一次)拼接成長度為N (0<N<=5)的字串,要求相同的字元不能相鄰,計算出給定的字元列表能拼接出多少種滿足條件的字串,輸入非法或者無法拼接出滿足條件的字串則返回0。
輸入
給定的字元列表和結果字串長度,中間使用空格(" ")拼接
輸出
滿足條件的字串個數
樣例輸入
aabc 3
樣例輸出
8
提示
給定的字元為aabc,結果字串長度為3,可以拼接成abc,acb,bac,bca,cba,cab,aba,aca,共8種
要解決這個問題,我們需要生成所有可能的長度為 ( N ) 的字串組合,並確保在這些組合中,相同的字元不能相鄰。可以透過回溯演算法來完成這個任務。具體步驟如下:
步驟
-
解析輸入:從輸入中提取字元列表和目標字串的長度 ( N )。
-
生成所有可能的字串:
- 使用回溯法生成所有可能的字串組合,確保在生成的過程中不會出現相同的字元相鄰的情況。
-
去重並計算符合條件的字串數:
- 將符合條件的字串存入集合中,以自動處理重複情況。
Java 實現
以下是一個 Java 實現程式碼,它解決了這個問題:
import java.util.HashSet;
import java.util.Scanner;
import java.util.Set;
public class UniqueStringGenerator {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
String chars = scanner.next();
int length = scanner.nextInt();
scanner.close();
// Check for invalid input
if (length <= 0 || length > 5 || chars == null || chars.isEmpty()) {
System.out.println(0);
return;
}
// Generate all valid strings
Set<String> result = new HashSet<>();
generateValidStrings(chars, length, "", result);
// Output the result
System.out.println(result.size());
}
private static void generateValidStrings(String chars, int length, String current, Set<String> result) {
if (current.length() == length) {
result.add(current);
return;
}
for (int i = 0; i < chars.length(); i++) {
char ch = chars.charAt(i);
if (current.isEmpty() || current.charAt(current.length() - 1) != ch) {
generateValidStrings(chars.substring(0, i) + chars.substring(i + 1), length, current + ch, result);
}
}
}
}
說明
-
輸入解析:
- 從標準輸入讀取字元列表和目標字串長度。若輸入無效(長度不在 [1, 5] 範圍內或字元列表為空),直接返回0。
-
生成有效字串:
- 使用回溯演算法生成長度為 ( N ) 的所有可能字串。每次遞迴呼叫時,嘗試將當前字元加入字串,並檢查相鄰字元是否相同。
- 如果當前字串的長度等於 ( N ),則將其加入結果集合中。
-
去重和計數:
- 結果儲存在
Set
中以自動去重。最終輸出集合的大小,即滿足條件的字串數量。
- 結果儲存在
示例
對於輸入:
aabc 3
程式將輸出:
8
表示總共有8種滿足條件的字串。
題目描述
給定一個有向圖,圖中可能包含有環,圖使用二維矩陣表示,每一行的第一列表示起始節點,第二列表示終止節點,如 [0, 1] 表示從 0 到 1 的路徑。
每個節點用正整數表示。求這個資料的首節點與尾節點,題目給的用例會是一個首節點,但可能存在多個尾節點。同時圖中可能含有環。如果圖中含有環,返回 [-1]。
說明:入度為0是首節點,出度為0是尾節點。
輸入描述
第一行為後續輸入的鍵值對數量N(N ≥ 0)
第二行為2N個數字。每兩個為一個起點,一個終點.
輸出描述
輸出一行頭節點和尾節點。如果有多個尾節點,按從小到大的順序輸出
備註
如果圖有環,輸出為 -1
所有輸入均合法,不會出現不配對的資料
用例1
輸入
4
0 1 0 2 1 2 2 3
輸出
0 3
說明
用例2
輸入
2
0 1 0 2
輸出
0 1 2
要解決這個問題,我們需要處理有向圖的頂點和邊,識別首節點和尾節點,並檢查圖中是否存在環。以下是實現步驟和相應的 Java 程式碼:
步驟
-
解析輸入:
- 從輸入中讀取圖的邊資料,並構建圖的鄰接表表示。
-
計算節點的入度和出度:
- 使用兩個
HashSet
來記錄入度為 0 和出度為 0 的節點。 - 遍歷圖的所有邊來更新入度和出度資訊。
- 使用兩個
-
檢測圖中是否存在環:
- 使用拓撲排序來檢測圖是否有環。可以透過Kahn演算法(基於入度的拓撲排序)來完成此任務。
-
輸出結果:
- 如果圖中存在環,輸出
[-1]
。 - 否則,輸出所有的首節點和尾節點。
- 如果圖中存在環,輸出
Java 實現
以下是實現上述邏輯的 Java 程式碼:
import java.util.*;
public class GraphNodes {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int N = scanner.nextInt();
if (N == 0) {
System.out.println("[-1]");
return;
}
Map<Integer, Set<Integer>> adjList = new HashMap<>();
Map<Integer, Integer> inDegree = new HashMap<>();
Set<Integer> nodes = new HashSet<>();
// Read edges and build the graph
for (int i = 0; i < N; i++) {
int start = scanner.nextInt();
int end = scanner.nextInt();
// Update adjacency list
adjList.putIfAbsent(start, new HashSet<>());
adjList.putIfAbsent(end, new HashSet<>());
adjList.get(start).add(end);
// Update in-degrees
inDegree.put(end, inDegree.getOrDefault(end, 0) + 1);
inDegree.putIfAbsent(start, 0);
nodes.add(start);
nodes.add(end);
}
// Find all nodes with in-degree 0 and out-degree 0
Set<Integer> startNodes = new TreeSet<>();
Set<Integer> endNodes = new TreeSet<>();
for (int node : nodes) {
if (inDegree.getOrDefault(node, 0) == 0) {
startNodes.add(node);
}
if (adjList.getOrDefault(node, Collections.emptySet()).isEmpty()) {
endNodes.add(node);
}
}
// Check for cycles using Kahn's Algorithm
if (hasCycle(adjList, inDegree, nodes.size())) {
System.out.println("[-1]");
} else {
// Output start and end nodes
List<Integer> result = new ArrayList<>(startNodes);
result.addAll(endNodes);
System.out.println(result);
}
}
// Function to check if there is a cycle in the graph
private static boolean hasCycle(Map<Integer, Set<Integer>> adjList, Map<Integer, Integer> inDegree, int numNodes) {
Queue<Integer> queue = new LinkedList<>();
int count = 0;
// Start with nodes with in-degree 0
for (int node : inDegree.keySet()) {
if (inDegree.get(node) == 0) {
queue.add(node);
}
}
while (!queue.isEmpty()) {
int node = queue.poll();
count++;
for (int neighbor : adjList.getOrDefault(node, Collections.emptySet())) {
inDegree.put(neighbor, inDegree.get(neighbor) - 1);
if (inDegree.get(neighbor) == 0) {
queue.add(neighbor);
}
}
}
// If count of processed nodes is not equal to the number of nodes, there's a cycle
return count != numNodes;
}
}
說明
-
輸入解析:
- 從輸入中讀取圖的邊資訊,並使用
HashMap
和HashSet
構建圖的鄰接表和入度統計。
- 從輸入中讀取圖的邊資訊,並使用
-
入度和出度計算:
- 維護兩個集合來跟蹤入度為 0 和出度為 0 的節點。
-
環檢測:
- 使用拓撲排序的 Kahn 演算法來檢測圖是否存在環。如果所有節點都能被處理,那麼圖沒有環,否則存在環。
-
輸出:
- 如果圖存在環,輸出
[-1]
。 - 否則,輸出首節點和尾節點。
- 如果圖存在環,輸出
示例
對於輸入:
4
0 1 0 2 1 2 2 3
程式將輸出:
0 3
表示首節點是0,尾節點是3。
對於輸入:
2
0 1 0 2
程式將輸出:
0 1 2
表示首節點是0,尾節點是1和2。