精简Linux的文件路径:
- ..回退的功能
- .留在当前文件夹
- //仅仅保留一个/
- abc/..要返回.
- 报错
- 删除最后一个/
主要思路: 用栈记录路径的起始位置,讨论/后的不同情况就可以:
#include <iostream> #include <map> #include <algorithm> #include <limits.h> #include <assert.h> #include <stack> using namespace std; int selectK(int num[], int k, int l, int r) { assert(k <= (r - l + 1) && k >= 1); int mid = (l + r) / 2, i = l, j = r; while (i <= j) { while (num[i] < num[mid]) { ++i; } while (num[j] > num[mid]) { --j; } if (i <= j) { swap(num[i],num[j]); ++i,--j; } } if (k == i - l) return num[i - 1]; else if (k < i - l) return selectK(num, k, l, i -1); else if (k == j + 1 - l) return num[j + 1]; else return selectK(num, k - (j - l + 2), j + 2, r); } void pathcompress(char* str) { int i = 0, j = 0; char prev = '\0'; stack<int> offset; offset.push(0); while(str[i]) { if (prev == '/') { if (str[i] == '.' && (str[i + 1] == '/' || str[i + 1] == '\0')) { prev = str[i + 1], i += 1; } else if (str[i] == '.' && str[i + 1] == '.' && (str[i + 2] == '/' || str[i + 2] == '\0')) { i += 2; if (offset.empty()) { cout << "error" << endl; return; } j = offset.top(); offset.pop(); if (offset.empty() && str[0] == '/') { cout << "error" << endl; return; } } else if (str[i] == '/') { prev = str[i++]; } else { offset.push(j); prev = str[i]; str[j++] = str[i++]; } } else { prev = str[i]; str[j++] = str[i++]; } } if (j >=3 && str[j - 1] == '/' && str[j-2] == '/') str[j-2] = '\0'; else if (j >= 2 && str[j - 1] == '/') str[j-1] = '\0'; else str[j] = '\0'; if (str[0] == '\0'){ str[0] = '.'; str[1] = '\0'; } } int main() { int num[] = {3,2,1,4,5}; int res1 = selectK(num, 1, 0, 4); int res2 = selectK(num, 2, 0, 4); int res3 = selectK(num, 3, 0, 4); int res4 = selectK(num, 4, 0, 4); int res5 = selectK(num, 5, 0, 4); // int res6 = selectK(num, 6, 0, 4); //char str[] = "////"; char str[] = "/.abc/xxx./abc/bacd/.././bcd/fsgs/../../../x/y/z/../../../.."; pathcompress(str); printf("%s\n",str); return 0; }
BUT this isn't right, For example: char str[] = "../../../etc/xyz/../abc"; You couldn't print error here. The right solution is:
You must distinguish the differences with the headers ../ and dir/
The concise version is :
#include <iostream> #include <map> #include <algorithm> #include <limits.h> #include <assert.h> #include <stack> using namespace std; int selectK(int num[], int k, int l, int r) { assert(k <= (r - l + 1) && k >= 1); int mid = (l + r) / 2, i = l, j = r; while (i <= j) { while (num[i] < num[mid]) { ++i; } while (num[j] > num[mid]) { --j; } if (i <= j) { swap(num[i],num[j]); ++i,--j; } } if (k == i - l) return num[i - 1]; else if (k < i - l) return selectK(num, k, l, i -1); else if (k == j + 1 - l) return num[j + 1]; else return selectK(num, k - (j - l + 2), j + 2, r); } void pathcompress2(char* str) { stack<int> path; int i = 0, j = 0; bool isRoot = (str[0] == '/'); char prev = '\0'; int len = strlen(str); if (!(len >= 3 && str[0] == '.' && str[1] == '.' && str[2] == '/')) path.push(0); while(str[i]) { if (prev == '/') { if (str[i] == '.' && (str[i+1] == '/' || str[i+1] == '\0')) { prev = '/'; if (str[i+1] == '\0') { str[j] = '\0'; break; } i+=2; } else if (str[i] == '.' && str[i+1] == '.' && (str[i+2] == '/' || str[i+2] == '\0')) { if (path.empty()) { str[j++] = str[i]; str[j++] = str[i+1]; str[j++] = str[i+2]; prev = '/'; if (str[i+2] == '\0') { str[j] = '\0'; break; } i+=3; } else { j = path.top(); path.pop(); if (path.empty() && isRoot) { // The case : cd /.. printf("Error\n"); return; } if (str[i+2] == '\0') { str[j] = '\0'; break; } prev = '/'; i += 3; } } else if (str[i] == '/') prev = str[i++]; else { prev = str[i]; path.push(j); str[j++] = str[i++]; } } else { prev = str[i]; str[j++] = str[i++]; } } if (j >= 2 && str[j - 1] == '/') str[j-1] = '\0'; else str[j] = '\0'; if (str[0] == '\0'){ str[0] = '.'; str[1] = '\0'; } } int main() { int num[] = {3,2,1,4,5}; int res1 = selectK(num, 1, 0, 4); int res2 = selectK(num, 2, 0, 4); int res3 = selectK(num, 3, 0, 4); int res4 = selectK(num, 4, 0, 4); int res5 = selectK(num, 5, 0, 4); // int res6 = selectK(num, 6, 0, 4); char str[] = "/.abc/xxx./abc/bacd/.././bcd/fsgs/../../../x/y/z/../../../../.././././xda"; //char str[] = "asdf/.abc/xxx./abc/bacd/.././bcd/fsgs/../../../x/y/z/../../../../../../.././../.././././"; //char str[] = "/xyz/./bcd/fsgs/../../../x/y/z/../../../.."; //char str[] = "../../../etc/xyz/../abc/////////////////////////////.asdf/../../../../"; pathcompress2(str); printf("%s\n",str); return 0; }
The concise version is :
void pathcompress2(char* str) { stack<int> path; int i = 0, j = 0, len = strlen(str); bool isRoot = (str[0] == '/'); char prev = '\0'; if (!(len >= 3 && str[0] == '.' && str[1] == '.' && (str[2] == '/' || str[2] == '\0')) path.push(0); while(str[i]) { if (prev == '/') { if (str[i] == '.' && (str[i+1] == '/' || str[i+1] == '\0')) { prev = '/'; if (str[i+1] == '\0') { str[j] = '\0'; break; } i+=2; } else if (str[i] == '.' && str[i+1] == '.' && (str[i+2] == '/' || str[i+2] == '\0')) { if (path.empty()) { str[j++] = str[i],str[j++] = str[i+1],str[j++] = str[i+2],prev = '/'; } else { j = path.top(); path.pop(); if (path.empty() && isRoot) { // The case : cd /.. printf("Error\n"); return; } } if (str[i+2] == '\0') { str[j] = '\0'; break; } prev = '/',i += 3; } else if (str[i] == '/') prev = str[i++]; else { prev = str[i],path.push(j),str[j++] = str[i++]; } } else { prev = str[i],str[j++] = str[i++]; } } if (j >= 2 && str[j - 1] == '/') str[j-1] = '\0'; else str[j] = '\0'; if (str[0] == '\0'){ str[0] = '.',str[1] = '\0'; } }