这是我在科技面试中遇到的一个问题。您在一个目录中有500万个文件,该目录被配置为始终按字母顺序排列。他们有这样的名字:
..。
您希望重命名所有文件,同时保留它们的order如下:
..。
你可能会在这里看到一个明显的问题。如果将Afile重命名为File00000001,它将与同名的现有文件发生冲突,顺序也将被更改,这不是我们想要的。
这里的问题是,如何设计一个具有最优运行时间的算法来高效地完成重命名任务?
发布于 2018-03-10 10:09:20
您不能按升序和不按递减顺序遍历文件,这两者都可能导致冲突。另外,首先将文件重命名为其他文件可能会导致冲突。目标似乎是只重命名每个文件一次,因此您可以这样做:
private static File dir;
public static void renameFiles(String path) {
dir = new File(path);
File[] files = dir.listFiles();
Map<String, String> map = new HashMap<>();
int number = 1;
for (int i = 0; i < files.length; i++)
if (files[i].isFile())
map.put(files[i].getName(), "File" + pad(number++));
// so we created a map with original file names and the name it should get
for (int i = 0; i < files.length; i++)
if (!files[i].getName().equals(map.get(files[i].getName())) // not same name
renameFile(files[i].getName(), map);
}
private static void renameFile(String file, Map<String, String> map) {
String newName = map.get(file);
if (newName != null) {
if (map.containsKey(newName))
renameFile(newName, map)
File f = new File(dir, file);
f.renameTo(new File(dir, newName));
map.remove(file);
}
}
时间复杂度O(n)我们递归地继续前进,直到不再有重命名冲突,然后开始从尾部重命名。不会发生冲突,因为可能File004变成File007,或者File007变成File004,但两者都不是,所以没有循环重命名。如果有太多的文件,那么递归深度可能是不够的,我们必须用堆栈来实现它,但这是相同的原则。
private static void renameFile(String file, Map<String, String> map) {
String newName = map.get(file);
if (newName != null) {
Stack<String> stack = new Stack<>();
do {
stack.push(file);
file = newName;
newName = map.get(file);
} while (newName != null);
while (!stack.empty()) {
file = stack.pop();
File f = new File(dir, file);
f.renameTo(new File(dir, map.get(file)));
map.remove(file);
}
}
}
这将在Linux上工作,但是对于Windows,您可能仍然会遇到问题,因为文件名不区分大小写。您可以将映射中的所有键作为小写存储,并在访问映射时始终调用toLowerCase()。
发布于 2018-03-10 11:20:56
for i in {100..1..-1} ; do o=$(printf "File%04d" $i); n=$(printf "File%04d" $((i + 2))); echo mv $o $n; done;
或更易读的:
for i in {100..1..-1}
do
o=$(printf "File%04d" $i)
n=$(printf "File%04d" $((i + 2)))
echo mv $o $n
done
FileA和FileB可以手工重命名。
您必须调整大小,但是对于测试来说,人工数量的文件对我来说似乎更合适。
啊,是的,这是bash语法;注意到这一点很重要。它还没有mv文件,只是回覆mv-命令。
不要试图并行运行它。:)
但是你也可以将它们按相反的,正常的顺序移动到一个新的dir,然后将它们全部移回旧的dir,以防止压倒一切。这将允许并行执行。
for-语句等效于其他已知的语句。
for (i = 100; i >=1; --i)
和
printf "File%04d" $i
打印带前导零的4位数字i。
https://stackoverflow.com/questions/49206053
复制相似问题