在给定的区间集合 X 互不重叠的前提下,当我们需要插入一个新的区间 S=[left,right] 时,我们只需要:
找出所有与区间 SSS 重叠的区间集合 X’;
将 X’中的所有区间连带上区间 SSS 合并成一个大区间;
最终的答案即为不与 X‘ 重叠的区间以及合并后的大区间。
这样做的正确性在于,给定的区间集合中任意两个区间都是没有交集的,因此所有需要合并的区间,就是所有与区间 S 重叠的区间。
并且,在给定的区间集合已经按照左端点排序的前提下,所有与区间 S 重叠的区间在数组 intervals 中下标范围是连续的,因此我们可以对所有的区间进行一次遍历,就可以找到这个连续的下标范围。
当我们遍历到区间 [li,ri]时:
如果ri<left,说明 [li,ri] 与 S 不重叠并且在其左侧,我们可以直接将[li,ri] 加入答案;
如果 li>right,说明[li,ri] 与 S 不重叠并且在其右侧,我们可以直接将 [li,ri] 加入答案;
如果上面两种情况均不满足,说明 [li,ri] 与 S 重叠,我们无需将[li,ri] 加入答案。此时,我们需要将 S 与 [li,ri] 合并,即将 S 更新为其与[li,ri] 的并集。
那么我们应当在什么时候将区间 S 加入答案呢?由于我们需要保证答案也是按照左端点排序的,因此当我们遇到第一个满足 li>right 的区间时,说明以后遍历到的区间不会与 S 重叠,并且它们左端点一定会大于 S 的左端点。此时我们就可以将 S 加入答案。特别地,如果不存在这样的区间,我们需要在遍历结束后,将 S 加入答案。
//C++ class Solution { public: vector<string> summaryRanges(vector<int>& nums) { vector<string> ret; int i = 0; int n = nums.size(); while (i < n) { int low = i; i++; while (i < n && nums[i] == nums[i - 1] + 1) { i++; } int high = i - 1; string temp = to_string(nums[low]); if (low < high) { temp.append("->"); temp.append(to_string(nums[high])); } ret.push_back(move(temp)); } return ret; } };
//Java class Solution { public List<String> summaryRanges(int[] nums) { List<String> ret = new ArrayList<String>(); int i = 0; int n = nums.length; while (i < n) { int low = i; i++; while (i < n && nums[i] == nums[i - 1] + 1) { i++; } int high = i - 1; StringBuffer temp = new StringBuffer(Integer.toString(nums[low])); if (low < high) { temp.append("->"); temp.append(Integer.toString(nums[high])); } ret.add(temp.toString()); } return ret; } }
//C++ class Solution { public: string reverseWords(string s) { int left = 0, right = s.size() - 1; // 去掉字符串开头的空白字符 while (left <= right && s[left] == ' ') ++left;
// 去掉字符串末尾的空白字符 while (left <= right && s[right] == ' ') --right;
deque<string> d; string word;
while (left <= right) { char c = s[left]; if (word.size() && c == ' ') { // 将单词 push 到队列的头部 d.push_front(move(word)); word = ""; } else if (c != ' ') { word += c; } ++left; } d.push_front(move(word)); string ans; while (!d.empty()) { ans += d.front(); d.pop_front(); if (!d.empty()) ans += ' '; } return ans; } };
//Java class Solution { public String reverseWords(String s) { int left = 0, right = s.length() - 1; // 去掉字符串开头的空白字符 while (left <= right && s.charAt(left) == ' ') { ++left; }
// 去掉字符串末尾的空白字符 while (left <= right && s.charAt(right) == ' ') { --right; }
Deque<String> d = new ArrayDeque<String>(); StringBuilder word = new StringBuilder(); while (left <= right) { char c = s.charAt(left); if ((word.length() != 0) && (c == ' ')) { // 将单词 push 到队列的头部 d.offerFirst(word.toString()); word.setLength(0); } else if (c != ' ') { word.append(c); } ++left; } d.offerFirst(word.toString());
//C++ class Solution { public: string convert(string s, int numRows) { if (numRows < 2) return s; vector<string> rows(numRows); int i = 0, flag = -1; for (char c : s) { rows[i].push_back(c); if (i == 0 || i == numRows -1) flag = - flag; i += flag; } string res; for (const string &row : rows) res += row; return res; } };
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
//Java class Solution { public String convert(String s, int numRows) { if(numRows < 2) return s; List<StringBuilder> rows = new ArrayList<StringBuilder>(); for(int i = 0; i < numRows; i++) rows.add(new StringBuilder()); int i = 0, flag = -1; for(char c : s.toCharArray()) { rows.get(i).append(c); if(i == 0 || i == numRows -1) flag = - flag; i += flag; } StringBuilder res = new StringBuilder(); for(StringBuilder row : rows) res.append(row); return res.toString(); } }
//C++ class Solution { public: int strStr(string haystack, string needle) { int n = haystack.size(), m = needle.size(); for (int i = 0; i + m <= n; i++) { bool flag = true; for (int j = 0; j < m; j++) { if (haystack[i + j] != needle[j]) { flag = false; break; } } if (flag) { return i; } } return -1; } };
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
//Java class Solution { public int strStr(String haystack, String needle) { int n = haystack.length(), m = needle.length(); for (int i = 0; i + m <= n; i++) { boolean flag = true; for (int j = 0; j < m; j++) { if (haystack.charAt(i + j) != needle.charAt(j)) { flag = false; break; } } if (flag) { return i; } } return -1; } }
复杂度分析
时间复杂度:O(n×m),其中 n 是字符串 haystack 的长度,m 是字符串 needle 的长度。最坏情况下我们需要将字符串 needle 与字符串 haystack 的所有长度为 m 的子串均匹配一次。
//C++ class Solution { // blank 返回长度为 n 的由空格组成的字符串 string blank(int n) { return string(n, ' '); }
// join 返回用 sep 拼接 [left, right) 范围内的 words 组成的字符串 string join(vector<string> &words, int left, int right, string sep) { string s = words[left]; for (int i = left + 1; i < right; ++i) { s += sep + words[i]; } return s; }
public: vector<string> fullJustify(vector<string> &words, int maxWidth) { vector<string> ans; int right = 0, n = words.size(); while (true) { int left = right; // 当前行的第一个单词在 words 的位置 int sumLen = 0; // 统计这一行单词长度之和 // 循环确定当前行可以放多少单词,注意单词之间应至少有一个空格 while (right < n && sumLen + words[right].length() + right - left <= maxWidth) { sumLen += words[right++].length(); }
// 当前行是最后一行:单词左对齐,且单词之间应只有一个空格,在行末填充剩余空格 if (right == n) { string s = join(words, left, n, " "); ans.emplace_back(s + blank(maxWidth - s.length())); return ans; }
int numWords = right - left; int numSpaces = maxWidth - sumLen;
//Java class Solution { public List<String> fullJustify(String[] words, int maxWidth) { List<String> ans = new ArrayList<String>(); int right = 0, n = words.length; while (true) { int left = right; // 当前行的第一个单词在 words 的位置 int sumLen = 0; // 统计这一行单词长度之和 // 循环确定当前行可以放多少单词,注意单词之间应至少有一个空格 while (right < n && sumLen + words[right].length() + right - left <= maxWidth) { sumLen += words[right++].length(); }
int numWords = right - left; int numSpaces = maxWidth - sumLen;
// 当前行只有一个单词:该单词左对齐,在行末填充剩余空格 if (numWords == 1) { StringBuffer sb = new StringBuffer(words[left]); sb.append(blank(numSpaces)); ans.add(sb.toString()); continue; }
// 当前行不只一个单词 int avgSpaces = numSpaces / (numWords - 1); int extraSpaces = numSpaces % (numWords - 1); StringBuffer sb = new StringBuffer(); sb.append(join(words, left, left + extraSpaces + 1, blank(avgSpaces + 1))); // 拼接额外加一个空格的单词 sb.append(blank(avgSpaces)); sb.append(join(words, left + extraSpaces + 1, right, blank(avgSpaces))); // 拼接其余单词 ans.add(sb.toString()); } }
// blank 返回长度为 n 的由空格组成的字符串 public String blank(int n) { StringBuffer sb = new StringBuffer(); for (int i = 0; i < n; ++i) { sb.append(' '); } return sb.toString(); }
// join 返回用 sep 拼接 [left, right) 范围内的 words 组成的字符串 public StringBuffer join(String[] words, int left, int right, String sep) { StringBuffer sb = new StringBuffer(words[left]); for (int i = left + 1; i < right; ++i) { sb.append(sep); sb.append(words[i]); } return sb; } }
public: int romanToInt(string s) { int ans = 0; int n = s.length(); for (int i = 0; i < n; ++i) { int value = symbolValues[s[i]]; if (i < n - 1 && value < symbolValues[s[i + 1]]) { ans -= value; } else { ans += value; } } return ans; } };
public int romanToInt(String s) { int ans = 0; int n = s.length(); for (int i = 0; i < n; ++i) { int value = symbolValues.get(s.charAt(i)); if (i < n - 1 && value < symbolValues.get(s.charAt(i + 1))) { ans -= value; } else { ans += value; } } return ans; } }