LeetCode-第 198 場周賽
5464.換酒問題
題目連結:5464.換酒問題
小區便利店正在促銷,用 numExchange
個空酒瓶可以兌換一瓶新酒。你購入了 numBottles
瓶酒。
如果喝掉了酒瓶中的酒,那麼酒瓶就會變成空的。
請你計算 最多 能喝到多少瓶酒。
樣例輸入與樣例輸出 Sample Input and Sample Output
示例 1:
輸入: numBottles = 9, numExchange = 3
輸出: 13
解釋: 你可以用 3 個空酒瓶兌換 1 瓶酒。
所以最多能喝到 9 + 3 + 1 = 13 瓶酒。
示例 2:
輸入: numBottles = 15, numExchange = 4
輸出:
解釋: 你可以用 4 個空酒瓶兌換 1 瓶酒。
所以最多能喝到 15 + 3 + 1 = 19 瓶酒。
示例 3:
輸入: numBottles = 5, numExchange = 5
輸出: 6
示例 4:
輸入: numBottles = 2, numExchange = 3
輸出: 2
提示 Hint
提示:
1 <= numBottles <= 100
2 <= numExchange <= 100
題解
暴力模擬即可。
class Solution { public: int closestToTarget(vector<int>& arr, int target) { set<int>a[2]; a[0].insert(INT_MAX); int ans(INT_MAX); for(int i = 0; i < arr.size(); ++i) { a[(i + 1) % 2].clear(); for(int j : a[i % 2]) { a[(i + 1) % 2].insert(j & arr[i]); ans = min(ans, abs((j & arr[i]) - target)); } a[(i + 1) % 2].insert(arr[i]); ans = min(ans, abs(arr[i] - target)); a[i % 2].clear(); } return ans; } };
5465.子樹中標籤相同的節點數
題目連結:5465.子樹中標籤相同的節點數
給你一棵樹(即,一個連通的無環無向圖),這棵樹由編號從 0
到 n - 1
的 n 個節點組成,且恰好有 n - 1
條 edges
。樹的根節點為節點 0
,樹上的每一個節點都有一個標籤,也就是字串 labels
中的一個小寫字元(編號為 i
的 節點的標籤就是
labels[i]
)
邊陣列 edges
以 edges[i] = [ai, bi]
的形式給出,該格式表示節點 ai
和 bi
之間存在一條邊。
返回一個大小為 n
的陣列,其中 ans[i]
表示第 i
個節點的子樹中與節點 i
標籤相同的節點數。
樹 T
T
中的某個節點及其所有後代節點組成的樹。
樣例輸入與樣例輸出 Sample Input and Sample Output
示例 1:
輸入: n = 7, edges = [[0,1],[0,2],[1,4],[1,5],[2,3],[2,6]], labels = "abaedcd"
輸出: [2,1,1,1,1,1,1]
解釋: 節點 0 的標籤為 'a' ,以 'a' 為根節點的子樹中,節點 2 的標籤也是 'a' ,因此答案為 2 。注意樹中的每個節點都是這棵子樹的一部分。
節點 1 的標籤為 'b' ,節點 1 的子樹包含節點 1、4 和 5,但是節點 4、5 的標籤與節點 1 不同,故而答案為 1(即,該節點本身)。
示例 2:
輸入: n = 4, edges = [[0,1],[1,2],[0,3]], labels = "bbbb"
輸出: [4,2,1,1]
解釋: 節點 2 的子樹中只有節點 2 ,所以答案為 1 。
節點 3 的子樹中只有節點 3 ,所以答案為 1 。
節點 1 的子樹中包含節點 1 和 2 ,標籤都是 'b' ,因此答案為 2 。
節點 0 的子樹中包含節點 0、1、2 和 3,標籤都是 'b',因此答案為 4 。
示例 3:
輸入: n = 5, edges = [[0,1],[0,2],[1,3],[0,4]], labels = "aabab"
輸出: [3,2,1,1,1]
示例 4:
輸入: n = 6, edges = [[0,1],[0,2],[1,3],[3,4],[4,5]], labels = "cbabaa"
輸出: [1,2,1,1,2,1]
示例 5:
輸入: n = 7, edges = [[0,1],[1,2],[2,3],[3,4],[4,5],[5,6]], labels = "aaabaaa"
輸出: [6,5,4,1,3,2,1]
提示 Hint
提示:
1 <= n <= 10^5
edges.length == n - 1
edges[i].length == 2
0 <= ai, bi < n
ai != bi
labels.length == n
labels
僅由小寫英文字母組成
題解
DFS 遍歷即可。
class Solution {
public:
vector<int> DFS(int root, int fa, vector<int>&ans, const vector<vector<int>>&g, const string &labels) {
vector<int>cnt(26, 0);
cnt[labels[root] - 'a']++;
for(int v : g[root]) {
if(v == fa)
continue;
vector<int>delta = DFS(v, root, ans, g, labels);
for(int j = 0; j < 26; ++j)
cnt[j] += delta[j];
}
ans[root] = cnt[labels[root] - 'a'];
return cnt;
}
vector<int> countSubTrees(int n, vector<vector<int>>& edges, string labels) {
if(n == 0)
return {};
vector<int>ans(n);
vector<vector<int>>g(n);
for(vector<int>edge : edges) {
g[edge[0]].push_back(edge[1]);
g[edge[1]].push_back(edge[0]);
}
DFS(0, -1, ans, g, labels);
return ans;
}
};
5466.最多的不重疊子字串
題目連結:5466.最多的不重疊子字串
給你一個只包含小寫字母的字串 s
,你需要找到 s
中最多數目的非空子字串,滿足如下條件:
- 這些字串之間互不重疊,也就是說對於任意兩個子字串
s[i..j]
和s[k..l]
,要麼j < k
要麼i > l
。 - 如果一個子字串包含字元
c
,那麼s
中所有c
字元都應該在這個子字串中。
請你找到滿足上述條件的最多子字串數目。如果有多個解法有相同的子字串數目,請返回這些子字串總長度最小的一個解。可以證明最小總長度解是唯一的。
請注意,你可以以 任意 順序返回最優解的子字串。
樣例輸入與樣例輸出 Sample Input and Sample Output
示例 1:
輸入: s = "adefaddaccc"
輸出: ["e","f","ccc"]
解釋: 下面為所有滿足第二個條件的子字串:
[
"adefaddaccc"
"adefadda",
"ef",
"e",
"f",
"ccc",
]
如果我們選擇第一個字串,那麼我們無法再選擇其他任何字串,所以答案為 1 。如果我們選擇 "adefadda" ,剩下子字串中我們只可以選擇 "ccc" ,它是唯一不重疊的子字串,所以答案為 2 。同時我們可以發現,選擇 "ef" 不是最優的,因為它可以被拆分成 2 個子字串。所以最優解是選擇 ["e","f","ccc"] ,答案為 3 。不存在別的相同數目子字串解。
示例 2:
輸入: s = "abbaccd"
輸出: ["d","bb","cc"]
解釋: 注意到解 ["d","abba","cc"] 答案也為 3 ,但它不是最優解,因為它的總長度更長。
提示 Hint
提示:
1 <= s.length <= 10^5
s
只包含小寫英文字母。
題解
找到所有子串,排序(短的優先),能加則加。
typedef pair<int, int>PII;
class Solution {
public:
vector<string> maxNumOfSubstrings(string s) {
if(s.length() == 0)
return {};
vector<PII>st;
vector<int>first_pos(26, -1), last_pos(26, -1);
for(int i = 0; i < 26; ++i) {
first_pos[i] = s.find_first_of('a' + i);
last_pos[i] = s.find_last_of('a' + i);
}
for(int i = 0; i < 26; ++i) {
size_t b = s.find_first_of('a' + i);
size_t e = s.find_last_of('a' + i);
if(b == string::npos)
continue;
for(bool redo = true; redo;) {
redo = false;
for(int j = b; j <= e; j++)
if(e < last_pos[s[j] - 'a'])
e = last_pos[s[j] - 'a'];
else if(b > first_pos[s[j] - 'a'])
b = first_pos[s[j] - 'a'], redo = true;
}
st.push_back({e - b + 1, b});
}
sort(st.begin(), st.end());
vector<bool>vis(s.length(), false);
vector<string>ans;
for(PII p : st) {
bool v = false;
for(int j = p.second; j < p.second + p.first; j++) {
if(vis[j]) {
v = true;
break;
}
}
if(v)
continue;
ans.push_back(s.substr(p.second, p.first));
for(int j = p.second; j < p.second + p.first; j++)
vis[j] = true;
}
return ans;
}
};
5467.找到最接近目標值的函式值
題目連結:5467.找到最接近目標值的函式值
Winston 構造了一個如上所示的函式 func
。他有一個整數陣列 arr
和一個整數 target
,他想找到讓 |func(arr, l, r) - target|
最小的 l
和 r
。
請你返回 |func(arr, l, r) - target|
的最小值。
請注意, func
的輸入引數 l
和 r
需要滿足 0 <= l, r < arr.length
。
樣例輸入與樣例輸出 Sample Input and Sample Output
示例 1:
輸入: arr = [9,12,3,7,15], target = 5
輸出: 2
解釋: 所有可能的 [l,r] 數對包括 [[0,0],[1,1],[2,2],[3,3],[4,4],[0,1],[1,2],[2,3],[3,4],[0,2],[1,3],[2,4],[0,3],[1,4],[0,4]], Winston 得到的相應結果為 [9,12,3,7,15,8,0,3,7,0,0,3,0,0,0] 。最接近 5 的值是 7 和 3,所以最小差值為 2 。
示例 2:
輸入: arr = [1000000,1000000,1000000], target = 1
輸出: 999999
解釋: Winston 輸入函式的所有可能 [l,r] 數對得到的函式值都為 1000000 ,所以最小差值為 999999 。
示例 3:
輸入: arr = [1,2,4,8,16], target = 0
輸出: 0
提示 Hint
提示:
1 <= arr.length <= 10^5
1 <= arr[i] <= 10^6
0 <= target <= 10^7
題解
法1.簡單的ST表預處理+二分答案
class Solution {
public:
int gao(vector<vector<int>>&d, int x, int y)const {
int k = log2(y - x + 1);
int ret = d[x][k] & d[y - (1 << k) + 1][k];
return ret;
}
int closestToTarget(vector<int>& arr, int target) {
int len = arr.size();
vector<vector<int>>d(len, vector<int>(20));
for(int i = 0; i < len; ++i)
d[i][0] = arr[i];
for(int j = 1; j <= log2(len); ++j) {
for(int i = 0; i + (1 << j) - 1 < len; ++i) {
d[i][j] = d[i][j - 1] & d[i + (1 << (j - 1))][j - 1];
}
}
int ans(0x7ffffff);
for(int i = 0; i < len; ++i) {
if(i && arr[i] == arr[i - 1])
continue;
int l = i, r = len - 1, mid;
if(gao(d, i, r) < target)
while(l < r) {
//cout<< l << " " << r<<endl;
mid = (l + r) >> 1;
if(gao(d, i, mid) > target)
l = mid + 1;
else
r = mid;
} else
l = r;
ans = min(ans, abs(gao(d, i, l) - target));
if(l - 1 >= i)
ans = min(ans, abs(gao(d, i, l - 1) - target));
}
return ans;
}
};
法2.暴力法(資料強度不是那麼的高)。對於每個以 i 位置結尾的,用 set 去重,可用滾動陣列的方式簡單優化下。
class Solution {
public:
int closestToTarget(vector<int>& arr, int target) {
set<int>a[2];
a[0].insert(INT_MAX);
int ans(INT_MAX);
for(int i = 0; i < arr.size(); ++i) {
a[(i + 1) % 2].clear();
for(int j : a[i % 2]) {
a[(i + 1) % 2].insert(j & arr[i]);
ans = min(ans, abs((j & arr[i]) - target));
}
a[(i + 1) % 2].insert(arr[i]);
ans = min(ans, abs(arr[i] - target));
a[i % 2].clear();
}
return ans;
}
};