目录
剑指Offer II 085. 生成匹配的括号
分析:
先生成n对括号,然后排序,求出排序序列的全排列逐个判断。
代码:
class Solution {
public:
bool check(string str) {
stack<char> st;
for(int i = 0; i < str.size(); i++) {
if(str[i] == '(') {
st.push(str[i]);
}else {
if(st.empty()) {
return false;
}else {
st.pop();
}
}
}
if(st.empty()) {
return true;
}else {
return false;
}
}
vector<string> generateParenthesis(int n) {
vector<string> res;
string temp = "";
for(int i = 0; i < n; i++) {
temp += "()";
}
sort(temp.begin(), temp.end());
do {
if(check(temp)) {
res.push_back(temp);
}
}while(next_permutation(temp.begin(), temp.end()));
return res;
}
};
剑指Offer II 009. 乘积小于 K 的子数组
分析:
双指针。
代码:
class Solution {
public:
int numSubarrayProductLessThanK(vector<int>& nums, int k) {
int res = 0;
int left = 0, right = 0;
int n = nums.size(), t = 1;
for(; right < n; right++) {
t *= nums[right];
while(left <= right && t >= k) {
t /= nums[left];
left++;
}
if(left <= right) {
res += (right - left + 1);
}
}
return res;
}
};
剑指Offer II 089. 房屋偷盗
剑指Offer II 010. 和为 k 的子数组
剑指Offer II 011. 0 和 1 个数相同的子数组
方法一:
前缀和:将数组中所有0变成-1,如果当前位置i的前缀和和位置j的前缀和相等,说明i到j之间的数组元素和为0,也即是拥有相同的0和1。
代码:
class Solution {
public:
int findMaxLength(vector<int>& nums) {
int n = nums.size();
vector<int> prefix(n);
nums[0] = nums[0] == 0 ? -1 : 1;
prefix[0] = nums[0];
for(int i = 1; i < n; i++) {
nums[i] = nums[i] == 0 ? -1 : 1;
prefix[i] = prefix[i-1] + nums[i];
}
int ans = INT_MIN;
for(int i = 0; i < n; i++) {
for(int j = i + 1; j < n; j++) {
if((prefix[j] - prefix[i] + nums[i]) == 0) {
ans = max(ans, j - i + 1);
}
}
}
return ans == INT_MIN ? 0 : ans;
}
};
方法二:
前缀和+哈希表:方法一中枚举左右边界超时。改进:利用哈希表存储前缀和,如果当前位置的前缀和在哈希表中出现过,说明两个位置的前缀和相等,一次遍历即可实现。
代码:
class Solution {
public:
int findMaxLength(vector<int>& nums) {
int n = nums.size();
unordered_map<int, int> mp;
mp[0] = -1;
int ans = INT_MIN;
int prefix = 0;
for(int i = 0; i < n; i++) {
prefix += nums[i] == 0 ? -1 : 1;
if(mp.find(prefix) != mp.end()) {
ans = max(ans, i - mp[prefix]);
}else {
mp[prefix] = i;
}
}
return ans == INT_MIN ? 0 : ans;
}
};
剑指Offer II 015. 字符串中的所有变位词
剑指Offer II 016. 不含重复字符的最长子字符串
剑指Offer II 019. 最多删除一个字符得到回文
方法一:
暴力枚举所有位置,删除后再判断,最后超时。
代码:
class Solution {
public:
bool check(string s) {
string t = s;
reverse(t.begin(), t.end());
return t == s;
}
bool validPalindrome(string s) {
if(check(s)) {
return true;
}
int n = s.size();
for(int i = 0; i < n; i++) {
string t = s;
t.erase(t.begin() + i);
if(check(t)) {
//cout << t << endl;
return true;
}
}
return false;
}
};
方法二:
双指针:两个指针l和r分别指向首尾元素,如果两个位置元素相等,说明满足回文条件,l++ r- -继续判断;如果不相等说明不满足回文条件,删除首尾元素分别判断,如果删除后是个回文串则说明可以得到回文串,否则永远不能得到回文串。
代码:
class Solution {
public:
bool check(string s) {
string t = s;
reverse(t.begin(), t.end());
return t == s;
}
bool validPalindrome(string s) {
if(check(s)) {
return true;
}
int l = 0, r = s.size() - 1;
while(l <= r) {
if(s[l] != s[r]) {
string t = s, f = s;
t.erase(t.begin() + l);
f.erase(f.begin() + r);
if(check(t) || check(f)) {
return true;
}else {
return false;
}
}
l++;
r--;
}
return true;
}
};
剑指Offer II 020. 回文子字符串的个数
剑指Offer II 021. 删除链表的倒数第 n 个结点
分析:
快慢指针:快慢指针初始时都指向第一个结点,快指针先移动n个位置,指向第n个结点,随后当快指针不为空时两个指针同时移动,当快指针指向空时,慢指针恰好指向倒数第n个结点。
代码:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
ListNode* removeNthFromEnd(ListNode* head, int n) {
ListNode* start = new ListNode(0, head);
ListNode* fast = start;
ListNode* slow = start;
for(int i = 0; i < n + 1; i++) {
fast = fast->next;
}
while(fast) {
fast = fast->next;
slow = slow->next;
}
slow->next = slow->next->next;
ListNode* ans = start->next;
delete start;
return ans;
}
};