Java 级联校验阵列形成的Leetcode解决方案
我已经测试了这个问题的基于字符串和基于映射的实现。第一个给出了12ms的运行时间,而第二个给出了1ms,两者使用的空间几乎相同。这两种样式的实现结构看起来是相同的。 所以,我想知道为什么两者在运行时有很大的不同。 以下是两种实现:Java 级联校验阵列形成的Leetcode解决方案,java,string,hashmap,Java,String,Hashmap,我已经测试了这个问题的基于字符串和基于映射的实现。第一个给出了12ms的运行时间,而第二个给出了1ms,两者使用的空间几乎相同。这两种样式的实现结构看起来是相同的。 所以,我想知道为什么两者在运行时有很大的不同。 以下是两种实现: class Solution { public boolean canFormArray(int[] arr, int[][] pieces) { // string based String str = &q
class Solution {
public boolean canFormArray(int[] arr, int[][] pieces) {
// string based
String str = "";
for (int i=0; i<arr.length; i++) {
str = str + arr[i] + "#";
}
for (int i=0; i<pieces.length; i++) {
String str2 = "";
for (int j=0; j<pieces[i].length; j++) {
str2 = str2 + pieces[i][j] + "#";
}
if (!str.contains(str2)) {
return false;
}
}
return true;
// map based
HashMap<Integer, Integer> map = new HashMap<>();
for (int i=0; i<arr.length; i++) {
map.put(arr[i], i);
}
for (int i=0; i<pieces.length; i++) {
if (!map.containsKey(pieces[i][0])) {
return false;
}
int index = map.get(pieces[i][0]);
for (int j=1; j<pieces[i].length; j++) {
if (!map.containsKey(pieces[i][j])) {
return false;
}
if (map.get(pieces[i][j]) != index+1) {
return false;
}
index++;
}
}
return true;
}
}
类解决方案{
公共布尔数组(int[]arr,int[]{
//基于字符串的
字符串str=“”;
因为(inti=0;i猜测str=str+arr[i]+“#”
和str2=str2+pieces[i][j]+“#”
在循环中创建新字符串。虽然创建对象不再是以前的重量级任务,但最好还是避免在循环中这样做
为了避免这种情况,请在循环外部创建StringBuilder,在循环内部使用append
方法,并在循环完成后使用toString()
。str.contains(str2)在最坏情况下的时间复杂度为O(nm)
而map.containsKey(片段[i][0])的时间复杂度为O(1)
请检查此答案以了解更多详细信息
- 类似的方法,在Java中也会采用:
- 如果我们只看一下Python版本,就会更容易理解:
HashMap.get和HashMap.containsKey都是O(1),而String.containsKey是O(n)。
public class Solution {
public static final boolean canFormArray(
final int[] arr,
final int[][] pieces
) {
StringBuilder sb = new StringBuilder();
for (int num : arr) {
sb.append(num);
sb.append("#");
}
for (int i = 0; i < pieces.length; i++) {
StringBuilder res = new StringBuilder();
for (int j = 0; j < pieces[i].length; j++) {
res.append(String.valueOf(pieces[i][j]));
res.append("#");
}
if (!sb.toString().contains(res.toString())) {
return false;
}
}
return true;
}
}
// Most of headers are already included;
// Can be removed;
#include <iostream>
#include <vector>
#include <unordered_map>
// The following block might slightly improve the execution time;
// Can be removed;
static const auto __optimize__ = []() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
std::cout.tie(nullptr);
return 0;
}();
struct Solution {
static const bool canFormArray(
const std::vector<int>& arr,
const std::vector<std::vector<int>>& pieces
) {
std::unordered_map<unsigned int, std::vector<int>> starts_partitions;
for (const auto& piece : pieces) {
starts_partitions[piece[0]] = piece;
}
std::vector<int> form_array;
for (const auto& num : arr) {
form_array.insert(
std::end(form_array),
std::begin(starts_partitions[num]),
std::end(starts_partitions[num])
);
}
return form_array == arr;
}
};
// int main() {
// std::cout << Solution().canFormArray({85}, {{85}}) << "\n";
// std::cout << Solution().canFormArray({15, 88}, {{88}, {15}}) << "\n";
// std::cout << Solution().canFormArray({49, 18, 16}, {{16, 18, 49}}) << "\n";
// std::cout << Solution().canFormArray({91, 4, 64, 78}, {{78}, {4, 64}, {91}}) << "\n";
// std::cout << Solution().canFormArray({1, 3, 5, 7}, {{2, 4, 6, 8}}) << "\n";
// };
class Solution:
def canFormArray(self, arr: List[int], pieces: List[List[int]]) -> bool:
starts_pieces = {piece[0]: piece for piece in pieces}
form_array = []
for num in arr:
form_array += starts_pieces.get(num, [])
return form_array == arr