除了前面25道题目,为了省时间,后面只做hard的题目
part1包含了1000题以内的题目(未加锁部分hard题)
500-1000见LeetCode题解part2
1000题以上的见LeetCode题解part3
1. Two Sum (Easy)
题意:给一个数组和一个数,求数组中哪两个数的和为这个数
题解:先排序,然后两个指针扫。容易证明这是可以的。因为如果当前的某个指针和已经扫过的某个数的和为目标值,那么则不可能达到现在这个状态。
时间复杂度是O(nlogn),不过如果数字都比较小,可以用计数的方法查找另一个数是否存在(或者用hash),这个解法为O(n)的解法。
语言:C++
#include <iostream>
#include <vector>
#include <algorithm>
#include <stdlib.h>
#include <assert.h>
using namespace std;
class Solution {
struct Node{
int value;
int index;
const bool operator < (const Node & b) {
return value < b.value;
}
};
public:
vector<int> twoSum(vector<int> &nums, int target) {
int len = nums.size();
Node *node = new Node[nums.size()];
for(size_t i = 0;i < nums.size(); ++i){
node[i].value = nums[i];
node[i].index = i;
}
sort(node, node + len);
size_t left = 0, right = len - 1;
int idL = - 1, idR = -1;
while(left < right){
if(node[left].value + node[right].value == target){
idL = node[left].index;
idR = node[right].index;
break;
}else if(node[left].value + node[right].value < target){
++left;
}else{
--right;
}
}
delete node;
assert(idL != -1);
vector<int> ans(2);
ans[0] = idL;
ans[1] = idR;
return ans;
}
};
int main()
{
vector<int> num(3);
int target = 6;
num[0] = 3; num[1] = 2; num[2] = 4;
Solution s;
vector<int> ans = s.twoSum(num, target);
cout<<ans[0]<<" "<<ans[1]<<endl;
return 0;
}
2. Add Two Numbers (Medium)
题意:给两个链表,每个链表表示一个数字(逆序的,个位在最前面),求他们的和,返回同样的格式(一个链表)
题解:简单的模拟加法过程即可
语言:C++
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
ListNode rootNode(0);
ListNode *pCurNode = &rootNode;
int a = 0;
while (l1 || l2)
{
int v1 = (l1 ? l1->val : 0);
int v2 = (l2 ? l2->val : 0);
int temp = v1 + v2 + a;
a = temp / 10;
ListNode *pNode = new ListNode((temp % 10));
pCurNode->next = pNode;
pCurNode = pNode;
if (l1) l1 = l1->next;
if (l2) l2 = l2->next;
}
if (a > 0)
{
ListNode *pNode = new ListNode(a);
pCurNode->next = pNode;
}
return rootNode.next;
}
};
把上面的模换成下面的
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
ListNode rootNode(0);
ListNode *pCurNode = &rootNode;
int a = 0;
while (l1 || l2)
{
int v1 = (l1 ? l1->val : 0);
int v2 = (l2 ? l2->val : 0);
int temp = v1 + v2 + a;
a = temp > 9;
ListNode *pNode = new ListNode(temp - a * 10);
pCurNode->next = pNode;
pCurNode = pNode;
if (l1) l1 = l1->next;
if (l2) l2 = l2->next;
}
if (a > 0)
{
ListNode *pNode = new ListNode(a);
pCurNode->next = pNode;
}
return rootNode.next;
}
};
3. Longest Substring Without Repeating Characters(Medium)
题意:给定一个字符串,找出没有重复字符的最长子串。
题解:首先可以线性时间求解出当前字符上一次出现的位置,用一个数组last_pos保存下来。然后可以得到,一个子串(从begin开始到end位置结束的串),没有重复字符当且仅当在这个子串中last_pos() < b。
解法就是枚举子串开始位置i,然后用index索引枚举结束位置。注意到如果j > i,那么从j开始的最长不重复子串的末尾一定在以i开始的那个最长子串末尾的后面(至少相等)。也就是说index不用从i 枚举,而是从上一次枚举的位置开始,这样就保证了线性的时间,每次index都会加1。
渐进时间复杂度:O(n)
语言: python
class Solution(object):
def lengthOfLongestSubstring(self, s):
lens = len(s);
w = [-1] * 100;
last_pos = [0] * lens;
#pos位置的字符上一次出现的位置,第一次出现,标记为-1
for pos, c in enumerate(s):
last_pos[pos] = w[ord(c) - ord('a')];
w[ord(c) - ord('a')] = pos;
ans = 0;
index = 0;
for i in range(lens):
while(index < lens - 1 and last_pos[index + 1] < i):
index = index + 1;
ans = max(ans,index - i + 1);
return ans;
4. Median of Two Sorted Arrays (Hard)
题意:两个有序数组,求中值
题解:可以使用中间二分形式进行,每次判断中间的值的大小,舍弃不可能是答案的某个数组的一半,当数组一个已经为空时,直接得到答案。具体如下:
对于两个数组: a[apre, amid,asuf],b[apre,bmid,bsuf],pre表前半段,suf表后半段,mid表中间元素(pre和suf可为空)。则答案在这6个段中的一个。(假设pre和suf都非空,因为如果为空,答案显然)比较a[amid]和b[bmid],如果a[amid] < b[bmid],那么可以确定顺序的有a[apre] <= a[amid] <= b[bmid] <= b[bsuf]。故而可以根据实际情况舍弃掉a[apre]或者b[bsuf]。那什么情况舍弃哪一个呢?有比较多的情况需要考虑。这个 方法虽然可以,但是到最后又非常多的边界需要判断,非常容易混乱。而如果不是取中位,而是k/2位的话,边界简单得多,思路和上面一样,只不过舍弃的情况没那么复杂。
时间复杂度(O(logn)
#include <iostream>
#include <vector>
using namespace std;
double findKth(int *a, int m, int *b, int n, int k)
{
if (m > n)
return findKth(b, n, a, m, k);
if (m == 0)
return b[k - 1];
if (k == 1)
return a[0] < b[0] ? a[0] : b[0] ;
int pa = k / 2 < m ? k / 2 : m, pb = k - pa;
if (a[pa - 1] < b[pb - 1])
return findKth(a + pa, m - pa, b, n, k - pa);
else if (a[pa - 1] > b[pb - 1])
return findKth(a, m, b + pb, n - pb, k - pb);
else
return a[pa - 1];
}
double findMedianSortedArrays(int* A, int m, int* B, int n) {
int total = m + n;
if (total & 0x1)
return findKth(A, m, B, n, total / 2 + 1);
else
return (findKth(A, m, B, n, total / 2)
+ findKth(A, m, B, n, total / 2 + 1)) / 2;
}
int main()
{
int *a ,b[] = {1};
cout<<findMedianSortedArrays(a,0,b,1)<<endl;
}
5. Longest Palindromic Substring (Medium)
题意:最大回文子串
题解:manacher算法;枚举中心,利用前面的信息。具体见manacher算法,无需多说。
渐进时间复杂度(O(n))
#include <iostream>
#include <vector>
using namespace std;
class Solution {
public:
string longestPalindrome(string s) {
string str(s.size() * 2 + 3,'#');
str[0] = '$';
str[s.size() * 2 + 2] = '@';
for(size_t i = 0;i < s.size(); ++i){
str[i * 2 + 2] = s[i];
}
return findLongestPalindrome(str, s);
}
string findLongestPalindrome(string str, string s){
size_t *d = new size_t[str.size()];
size_t mx = 0, mxId = 0, longestLenth = 1 , longestLenthPos = 0;
d[0] = 1;
for(size_t i = 1;i < str.size(); ++i){
if(mx <= i) d[i] = 1;
else d[i] = min(d[2 * mxId - i] , mx - i);
while(str[i - d[i]] == str[i + d[i]]) ++d[i];
if(d[i] + i > mx){
mx = d[i] + i;
mxId = i;
}
if(d[i] > longestLenth){
longestLenth = d[i] - 1;
longestLenthPos = i;
}
}
delete d;
size_t startPos = (longestLenthPos - longestLenth) / 2;
return s.substr(startPos, longestLenth);
}
};
int main()
{
Solution s;
string str = "ccd";
cout<<s.longestPalindrome(str)<<endl;
}
6. ZigZag Conversion
题意:将一个字符串转化成zigZag形状,然后按行重新排列输出。
题解:简单模拟。
不过编译器好像跟本地的不太一样,对关于vector初始化,需要push_back过才能取出,否则是runtimeError 而不是取出空串。
代码:
#include <iostream>
#include <string>
#include <vector>
using namespace std;
string convert(string s, int nRows) {
if(nRows <= 1 || s.length() <= nRows)
return s;
vector<string> zigZags(nRows);
int curRow = 0, step = 1;
for (string::iterator s_iter = s.begin(); s_iter != s.end(); ++s_iter){
zigZags[curRow].push_back(*s_iter);
if(curRow == 0) step = 1;
else if(curRow == nRows - 1) step = -1;
curRow += step;
}
s.clear();
string::iterator s_it;
for(vector<string>::iterator vit = zigZags.begin(); vit != zigZags.end(); ++vit){
s += *vit;
}
return s;
}
int main()
{
string s = "PAYPALISHIRING;
int nRows = 3;
cout<<convert(s, nRows)<<endl;
return 0;
}
7. Reverse Integer
题意:将数字翻转
题解:直接转,注意前导零和溢出即可
代码:
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
using namespace std;
int reverse(int x) {
if (x == 0) return 0;
int sign = (x > 0) * 2 - 1;
long long y = abs(x);
long long res = 0;
while(y > 0){
res = res * 10 + y % 10;
y /= 10;
}
res = sign * res;
if(res > (1LL << 31) - 1 || res < -(1LL << 31))
res = 0;
return res;
}
int main()
{
cout<<reverse(-123)<<endl;
return 0;
}
8. String to Integer (atoi)
题意:按照题目将字符串转成int。规则是,前缀不合法输出前缀,合法前缀为空输出0,超出int输出maxint,小于minint输出minint即可
题解:主要是题目各种输入情况没有说明
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
using namespace std;
int myAtoi(string str) {
int sign = 1;
int max_int = 2147483647;
int min_int = -2147483648;
string::iterator s_it = str.begin();
while(s_it != str.end() && *s_it == ' ') ++s_it;
if(s_it != str.end() && (*s_it == '+' || *s_it == '-')){
sign = ((*s_it == '+') * 2 - 1);
++s_it;
}
long long res = 0;
int num = 0;
for(; s_it != str.end() ; ++ s_it){
if(*s_it < '0' || *s_it > '9') break;
res = res * 10 + sign * (*s_it - '0');
++num;
if(res > max_int) {
res = max_int;
break;
}
if(res < min_int){
res = min_int;
break;
}
}
if(num == 0) return 0;
return res;
}
int main()
{
cout<<myAtoi("1")<<endl;
return 0;
}
9. Palindrome Number
题意:判断一个整数是不是回文数
题解:将x的后半段倒置,然后和前半段比较即可,注意可能有奇数个数字或偶数,末尾有0,以及负数的情形即可。
class Solution {
public:
bool isPalindrome(int x) {
if(x < 0 || (x != 0 && x % 10==0))
return false;
int y = 0;
while(x > y){
y = y * 10 + x % 10;
x /= 10;
}
return (x == y) || (x == y / 10);
}
};
10. Regular Expression Matching
题意:简单的正则表达式,判断给定字符串是不是符合给定的模式(只包含字符和*以及.)
题解:按照多年的acm经验,一眼看出是简单DP题。
dp[i][j]表示字符串和0到i个位置的子串,是否能与模式串0到j匹配。然后就分几种情况进行转移即可。注意在前面增加了空串(即0为置表示空串),能够简化代码。
解如下:
设d[i][j]表示原字符串的0到i能否和模式串的0到j匹配。字符串从1位置开始,0表示空串(方便处理)
故d[0][0] = 1,下面求转移方程
分三种情况:
p[j] = '.', p[j] = '*’和其他
当p[j] = '*' 时,要使得d[i][j] = 1,必须有如下情况之一发生
a.d[i][j - 2] = 1 (p[j - 1], p[j] 匹配空串)
b.d[i - 1][j - 1] = 1且(s[i] = p[j - 1]或 p[j - 1] = '.')
当p[j] = '.', 要使得d[i][j] = 1,必须有
d[i - 1][j - 1] = 1
其他:
d[i - 1][j - 1] = 1且 s[i] = p[j]
class Solution {
public:
static const size_t maxN = 1000;
static bool dp[maxN][maxN];
bool isMatch(string s, string p) {
size_t slen = s.length();
size_t plen = p.length();
dp[0][0] = true;
for (size_t i = 0; i <= slen; ++i)
for (size_t j = 1; j <= plen; ++j)
if (p[j - 1] == '*')
dp[i][j] = dp[i][j - 2] || (i > 0 && (s[i - 1] == p[j - 2] || p[j - 2] == '.') && dp[i - 1][j]);
else dp[i][j] = i > 0 && dp[i - 1][j - 1] && (s[i - 1] == p[j - 1] || p[j - 1] == '.');
return dp[slen][plen];
}
};
bool Solution::dp[maxN][maxN];
11. Container With Most Water
题意:给定一组数据,d0,d1,...dn,表示第i个位置有长为di的竖线,问这些竖线中那两根和x轴围成的容器能装最多的水?
题解:考虑双指针。从两边开始,注意到,如果两个指针(i和j)的一边比较短,那么,这一个边就可以抛弃掉,因为它不可能是最优解(不妨设i比较短(或者等长),假设它和另外一根线k组成最优解,那么k可能在i前面,ij中间,或者j后面。首先k不可能在i前面或者j后面,不然的话,我们不可能把k抛弃掉。另外,它也不可能在ij中间,因为如果在ij中间的话ik肯定没有ij这一对好,所以i可以抛弃掉)。
class Solution {
public:
int maxArea(vector<int>& height) {
int ans = 0, left = 0, right = height.size() - 1;
while (left < right) {
ans = max(ans, min(height[left], height[right]) * (right - left));
if (height[left] < height[right])
++left;
else
--right;
}
return ans;
}
};
12. Integer to Roman
题意:将一个整数转换成罗马数字(罗马数字参考http://baike.baidu.com/link?url=uhmgSPP-MZpOKblUj9gO6pvpuLzgx2XteJGqyPoJjmrTpRZ8H_Jx_WUz2gmIxMwnLKKZKpnkPOUVbkMc4RY0fjYjnYU4Y6snyWn0lmLXu9gHxsUoLi7PgJBr_cdm-NNd)
数字在1到3999之间
简单题,这是别人写的代码
class Solution {
public:
string intToRoman(int num) {
string M[] = {"", "M", "MM", "MMM"};
string C[] = {"", "C", "CC", "CCC", "CD", "D", "DC", "DCC", "DCCC", "CM"};
string X[] = {"", "X", "XX", "XXX", "XL", "L", "LX", "LXX", "LXXX", "XC"};
string I[] = {"", "I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX"};
return M[num / 1000] + C[(num % 1000) / 100] + X[(num % 100) / 10] + I[num % 10];
}
};
13. Roman to Integer
题意:将罗马数字转换成整数
题解:简单题
别人的代码:http://blog.csdn.net/booirror/article/details/43197595
class Solution {
public:
int getVal(char a){
switch (a) {
case 'I':
return 1;
case 'V':
return 5;
case 'X':
return 10;
case 'L':
return 50;
case 'C':
return 100;
case 'D':
return 500;
case 'M':
return 1000;
}
return 0;
}
int romanToInt(string s){
int res = 0;
char max = 'I';
for (int i = s.size()-1; i >= 0; --i) {
if (getVal(s[i]) >= getVal(max)) {
max = s[i];
res += getVal(s[i]);
} else {
res -= getVal(s[i]);
}
}
return res;
}
};
14. Longest Common Prefix
题意:给定一个字符串数组,找出他们的最长公共前缀。
题解:简单题
class Solution {
public:
string longestCommonPrefix(vector<string>& strs) {
string prefix = "";
if(strs.size() < 1) return prefix;
for(size_t i = 0; i < strs[0].size();prefix += strs[0][i++])
for(size_t j = 0;j < strs.size(); ++j)
if(i >= strs[j].size() || strs[j][i] != strs[0][i]) return prefix;
return prefix;
}
};
15. 3Sum
题意:给定一个数组,三个数和为0的数对有哪些
题解:为了避免重复,先排序。先枚举第一个数,然后2和3 用two sum的方法。下面代码修改自
1.two sum(不过这里不需要给出下标),渐进时间复杂度为)(n^2)。容易改成计数或者hash的做法,这里不给出。
quadruple
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
sort(nums.begin(), nums.end());
vector<vector<int>> ans;
int len = nums.size();
for(size_t i = j + 1; i < len; ++i){
int target = -nums[i] - nums[j];
size_t left = i + 1, right = len - 1;
while(true){
while(left > i + 1 && left < right && nums[left] == nums[left - 1]) ++left;
while(right < len - 1 && left < right && nums[right] == nums[right + 1]) --right;
if(left >= right) break;
if(nums[left] + nums[right] == target){
vector<int> triplet(3, 0);
triplet[0] = nums[i];
triplet[1] = nums[left++];
triplet[2] = nums[right--];
ans.push_back(triplet);
}else if(nums[left] + nums[right] < target){
++left;
}else{
--right;
}
}
}
return ans;
}
};
16. 3Sum Closest
题意:给定一个数组和一个目标值,求离目标最近的三个数的和是多少?
题解:和15没啥不一样,改一下代码即可
class Solution {
public:
int threeSumClosest(vector<int>& nums, int target) {
sort(nums.begin(), nums.end());
int len = nums.size();
int ans = nums[0] + nums[1] + nums[2];
int dis = abs(ans - target);
for(size_t i = 0; i < len; ++i){
if(i > 0 && nums[i] == nums[i - 1]) continue;
size_t left = i + 1, right = len - 1;
int T = target - nums[i];
while(true){
while(left > i + 1 && left < right && nums[left] == nums[left - 1]) ++left;
while(right < len - 1 && left < right && nums[right] == nums[right + 1]) --right;
if(left >= right) break;
if(abs(nums[left] + nums[right] - T) < dis){
dis = abs(nums[left] + nums[right] - T);
ans = nums[left] + nums[right] + nums[i];
}
if(dis == 0) break;
if(nums[left] + nums[right] < T){
++left;
}else{
--right;
}
}
}
return ans;
}
};
17. Letter Combinations of a Phone Number
题意:给定一串数字字符串,问按照电话上的字母转换规则,能转换成那些字母的字符串。
题解:可以有多种方法解决,我是利用计数迭代的方法,遍历所有的排列。
class Solution {
public:
vector<string> letterCombinations(string digits) {
string kvmaps[8] = {"abc", "def", "ghi", "jkl", "mno", "pqrs", "tuv", "wxyz" };
int length[8] = {3,3,3,3,3,4,3,4};
vector<string> ans;
if(digits == "") return ans;
vector<int> iter(digits.size(),0);
bool flag = true;
int digit;
while(flag){
string s = "";
for(int i = 0 ; i < digits.size(); ++i){
digit = digits[i] - '0';
if(digit == 0) digit = 10;
s += kvmaps[digit - 2][iter[i]];
}
ans.push_back(s);
++iter[0];
for(int i = 0; i < digits.size(); ++i){
digit = digits[i] - '0';
if(digit == 0) digit = 10;
if(iter[i] >= length[digit - 2]){
if(i == digits.size() - 1){flag = false; break;}
else{
iter[i] = 0;
++iter[i + 1];
}
}
}
}
return ans;
}
};
18. 4Sum
题意:给定一个数组和一个目标整数,求数组中不重复的四元组的和为目标的四元组
题解:在15题加一层循环即可
class Solution {
public:
vector<vector<int>> fourSum(vector<int>& nums,int T) {
sort(nums.begin(), nums.end());
vector<vector<int>> ans;
int len = nums.size();
for(size_t j = 0;j < len; ++j){
if(j > 0 && nums[j] == nums[j - 1]) continue;
for(size_t i = j + 1; i < len; ++i){
if(i > j + 1 && nums[i] == nums[i - 1]) continue;
int target = T - nums[i] - nums[j];
size_t left = i + 1, right = len - 1;
while(true){
while(left > i + 1 && left < right && nums[left] == nums[left - 1]) ++left;
while(right < len - 1 && left < right && nums[right] == nums[right + 1]) --right;
if(left >= right) break;
if(nums[left] + nums[right] == target){
vector<int> quadruples(4, 0);
quadruples[0] = nums[j];
quadruples[1] = nums[i];
quadruples[2] = nums[left++];
quadruples[3] = nums[right--];
ans.push_back(quadruples);
}else if(nums[left] + nums[right] < target){
++left;
}else{
--right;
}
}
}
}
return ans;
}
};
19. Remove Nth Node From End of List
题意:通过一次遍历,将链表的倒数第n个删掉
题解:虽然说是一次遍历,实际上只不过是两次遍历写在一个循环里面罢了。
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* removeNthFromEnd(ListNode* head, int n) {
ListNode* h1 = head, *h2 = head;
while(n-->0) h2 = h2->next;
if(!h2) return head->next;
h2 = h2->next;
while(h2 != NULL){
h1 = h1->next;
h2 = h2->next;
}
h1->next = h1->next->next; // the one after the h1 need to be removed
return head;
}
};
20. Valid Parentheses
题意: 给定一个包含三种括号的字符串,判断是否是合法的括号嵌套。
题解:模拟匹配过程即可
class Solution {
public:
bool isValid(string s) {
stack<char>S;
if(s.empty()) return true;
if(s[0] != '(' && s[0] != '[' && s[0] != '{') return false;
S.push(s[0]);
for(int i = 1;i < s.length(); ++i){
if(s[i] == ')' || s[i] == ']' || s[i] == '}'){
if(S.empty()) return false;
if(s[i] == ')' && S.top() != '(' || s[i] == ']' && S.top() != '[' || s[i] == '}' && S.top() != '{') return false;
S.pop();
}else{
S.push(s[i]);
}
}
return S.empty();
}
};
21. Merge Two Sorted Lists
题意:将两个有序链表合并(从小到大)
题解:简单题
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
if(l1 == NULL) return l2;
if(l2 == NULL) return l1;
ListNode * listHead, *p;
listHead = p = new ListNode(0);
while(l1 && l2){
if(l1->val < l2->val) {
p->next = l1;
l1 = l1->next;
}else{
p->next = l2;
l2 = l2->next;
}
p = p->next;
}
if(l1 != NULL) p->next = l1;
else p->next = l2;
p = listHead->next;
delete listHead;
return p;
}
};
22. Generate Parentheses
题意:给定一个n,生成所有可能长度为n的嵌套括号组合
题解:可以用dfs求解。不过我这里用bfs,然后用位标记法代替字符串以节省内存。
class Solution {
public:
vector<string> generateParenthesis(int n) {
vector<string> ans;
n *= 2;
//1是右括号,0为左括号
cout<<'yes';
queue<pair<long long,char> > Q;
Q.push(make_pair(0LL,0x01));
while(!Q.empty()){
pair<long long,char> p = Q.front();
Q.pop();
if(p.second == n){
ans.push_back(genString(p.first,n));
continue;
}
//添加左括号
char leftParenthesisNum = p.second - bitCount(p.first);
//cout<<leftParenthesisNum<<" p"<<endl;
if(leftParenthesisNum < n / 2) Q.push(make_pair(p.first,p.second + 1));
if(leftParenthesisNum > p.second - leftParenthesisNum)Q.push(make_pair(p.first | (1 << p.second), p.second + 1));1<<endl;
}
return ans;
}
//计算位数
char bitCount(unsigned long long n)
{
n = (n &0x5555555555555555) + ((n >>1) &0x5555555555555555) ;
n = (n &0x3333333333333333) + ((n >>2) &0x3333333333333333) ;
n = (n &0x0f0f0f0f0f0f0f0f) + ((n >>4) &0x0f0f0f0f0f0f0f0f) ;
n = (n &0x00ff00ff00ff00ff) + ((n >>8) &0x00ff00ff00ff00ff) ;
n = (n &0x0000ffff0000ffff) + ((n >>16) &0x0000ffff0000ffff) ;
n = (n &0x00000000ffffffff) + ((n >>32) &0x00000000ffffffff) ;
return char(n&0xff) ;
}
string genString(long long parentheses, int n){
string s = "";
for(int i = 0;i < n; ++i){
if((parentheses>>i) & 1) s+=')';
else s+= '(';
}
return s;
}
};
23. Merge k Sorted Lists
题意:将k个有序链表合并成一个
题解:用优先队列即可。主义c++优先队列是大顶堆
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
struct cmp
{
bool operator()(ListNode * &a,ListNode * &b){
return a->val > b->val;
}
};
ListNode* mergeKLists(vector<ListNode*>& lists) {
priority_queue<ListNode *,vector<ListNode *>, cmp>Q;
ListNode *head,*p;
head = p = new ListNode(0);
for(size_t i = 0;i < lists.size(); ++i)
if(lists[i] != NULL) Q.push(lists[i]);
while(!Q.empty()){
ListNode *node = Q.top();
Q.pop();
p->next = node;
p = p->next;
if(node->next) Q.push(node->next);
}
p = head->next;
delete head;
return p;
}
};
24. Swap Nodes in Pairs
题意:交换链表中的连续的对(交换(1,2),(3,4 ) 以此类推)。
题解:模拟即可
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* swapPairs(ListNode* head) {
int index = 0;
ListNode* l1, *l2, *tmp = new ListNode(0);
tmp->next = head;
head = tmp;
while(tmp){
if(!tmp->next) break;
l1 = tmp->next;
if(!l1->next) break;
l2 = l1->next;
tmp->next = l2;
l1->next = l2->next;
l2->next = l1;
tmp = l1;
}
tmp = head->next;
delete head;
return tmp;
}
};
31. Next Permutation
题意:给定一个数组,求排列中,下一个排列。
题解:注意可能有重复数字。模仿我们人计算过程。首先判断是否为最后一个排列,是就输出翻转后的结果。不然,将排列分成三部分(我们假设长度大于等于2,第一部分可为空)[a, b, c](a,c为序列,b为一个数字),其中c呈倒序,而且b小于c的第一个数字,那么下一个排列将为,a不变,将b和c最后一个大于它的数交换,然后将c翻转。(这个是很容易想到的,实现也简单)
class Solution {
public:
int decreaseLen(vector<int> & nums){
int len = 1;
for(int i = nums.size() - 2; i >= 0 && nums[i] >= nums[i + 1] ;--i,++len);
return len;
}
void nextPermutation(vector<int>& nums) {
if(nums.size() <= 1) return;
int len = decreaseLen(nums);
if(len == nums.size()){reverse(nums.begin(),nums.end());return;}
int id = nums.size() - len - 1;
int pos = id;
//找到后面最后一个大于它的数
for(int i = id + 1;nums[id] < nums[i] && i <= nums.size(); ++i)++pos;
pos = min(pos,int(nums.size() - 1) );
swap(nums[id],nums[pos]);
reverse(nums.begin() + id + 1,nums.end());
}
};
32. Longest Valid Parentheses
题意:给一个包含'('和')'的括号串,求最长的合法配对子括号串长度。
题解:动态规划,dp[i]表示以第i个位置作为结束时的最长串长度。
当s[i] == '('时,dp[i] = 0.
当s[i] == ')'时候,看前面那个配对到哪里,然后这个括号能否配对,如果不能,也是dp[i] = 0,能的话递推。
class Solution {
public:
int longestValidParentheses(string s) {
int n = s.length();
if(n <= 1) return 0;
vector<int> dp(n);
int ans = 0;
dp[0] = 0;
for(int i = 1; i < n; ++i){
if(s[i] == '(') dp[i] = 0;
else{
if(s[i - 1] == '('){
if(i == 1) dp[i] = 2;
else dp[i] = dp[i - 2] + 2;
}else{
int idx = i - 1 - dp[i - 1];
if(idx >= 0 && s[idx] == '('){
if(idx > 0)
dp[i] = dp[i - 1] + dp[idx - 1] + 2;
else dp[i] = dp[i - 1] + 2;
}else dp[i] = 0;
}
}
ans = max(ans,dp[i]);
}
return ans;
}
};
在s前面补一个'('可以少个两个判断条件。
class Solution {
public:
int longestValidParentheses(string s) {
int n = s.length();
if(n <= 1) return 0;
s = ')' + s; ++n;
vector<int> dp(n);
int ans = 0;
dp[0] = dp[1] = 0;
for(int i = 2; i < n; ++i){
if(s[i] == '(') dp[i] = 0;
else{
if(s[i - 1] == '('){
if(i == 1) dp[i] = 2;
else dp[i] = dp[i - 2] + 2;
}else{
int idx = i - 1 - dp[i - 1];
if(s[idx] == '('){
dp[i] = dp[i - 1] + dp[idx - 1] + 2;
}else dp[i] = 0;
}
}
ans = max(ans,dp[i]);
}
return ans;
}
};
37. Sudoku Solver
题意:求解一个数独
题解:深度搜索和剪枝
‘class Solution {
public:
void solveSudoku(vector<vector<char>>& board) {
vector<vector<bool> >rowVis(9,vector<bool>(9,false));
vector<vector<bool> >colVis(9,vector<bool>(9,false));
vector<vector<bool> >lat (9,vector<bool>(9,false));
for(int i = 0;i < 9; ++i)
for(int j = 0;j < 9; ++j){
if(board[i][j] == '.') continue;
int x = board[i][j] - '1';
rowVis[i][x] = colVis[j][x] = lat[(i / 3) * 3 + j / 3][x] = true;
}
dfs(board,rowVis,colVis,lat,0,0);
}
bool dfs(vector<vector<char>>& board,vector<vector<bool> >& rowVis,vector<vector<bool> >& colVis,vector<vector<bool> >&lat,int x,int y){