1.Easy
map中,map[一个不存在的key]返回整型Int0。程序容易出错在如果第一格是正确答案也是0.
因此可以用map.find(key) == map.end()来做。
3.Easy
整数最大范围:Integer.Max_VALUE
27.Easy
用迭代器来删除erase数组中的某些元素:注意删除的那一次循环不要再it++了。因为在进行单个元素删除后,传入的迭代器指向不变,仍然指向被删除元素的位置,而被删除元素之后的所有元素都向前移动一位,也就是该迭代器实际上是指向了原来被删除元素的下一个元素。
for(auto it = vec.begin();it != vec.end();)
{
if(*it == value)
vec.erase(it);
else
it++;
}
136.只出现一次的数字 (异或)
方法一:先排序,然后每次跳两格遍历。如果当前元素不等于后面一个元素,直接返回。如果全等于,就会遍历到最后一个元素,这时最后一个元素一定是落单的,返回最后一个元素。 并且,做一个return -1的异常捕获。
方法二:把所有数字做异或运算,最后结果就是落单的。
异或 :相同结果为0,不同结果为1
a 异或0 = a;
a异或a = 0;
异或符号 : a ^ b
137.环形链表 (快慢指针,哈希表)
利用快慢指针:
class Solution {
public:
bool hasCycle(ListNode *head) {
if(head == NULL || head->next == NULL)
return false;
ListNode* slow = head;
ListNode* fast = head->next;
while(slow != fast)
{
if(fast == NULL || fast->next == NULL)
return false;
slow = slow->next;
fast = fast->next->next;
}
return true;
}
};
哈希法:
class Solution {
public:
bool hasCycle(ListNode *head) {
map<ListNode* , int> m;
while(head)
{
m[head]++;
if(m[head] > 1) return true;//重复出现立刻跳出
head = head->next;
}
return false;
}
};
141.环形链表 双指针跳转
因为俩链表不同长度,所以用alen + blen = blen + alen的特性解决问题。在it1 = NULL时,另it1 = headB。当第二次又走到末尾的时候,it1和it2同时为NULL。
两个NULL是相等的,所以自动跳出了循环。
class Solution {
public:
ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
ListNode* it1 = headA;
ListNode* it2 = headB;
if(it1 == NULL || it2 == NULL) return NULL;
while(it1 != it2)
{
if(it1 == NULL)
it1 = headB;
else
it1 = it1->next;
if(it2 == NULL)
it2 = headA;
else
it2 = it2->next;
}
return it1;
}
};
167.两数之和[2] 哈希表,双指针
除了用1中的哈希表方法,还可以用头尾双指针来做。
因为序列已经是有序的了,所以将两数和sum和target判断,如果相等则推入result数组,如果大于则尾指针前移,如果小于则头指针后移。
class Solution {
public:
vector<int> twoSum(vector<int>& numbers, int target) {
vector<int> res;
int i = 0, j = numbers.size() -1;
while (i <= j)
{
int sum = numbers[i] + numbers[j];
if (sum == target)
{
res.push_back(i + 1);
res.push_back(j + 1);
return res;
}
else if (sum < target)
i++;
else if (sum > target)
j--;
}
return res;
}
};
169.多数元素 哈希表,分而治之(暂时不会)
class Solution {
public:
int majorityElement(vector<int>& nums) {
map<int,int> m;
int n = nums.size();
for(int i = 0;i < n;i++)
{
if(m.find(nums[i])==m.end() )
m[nums[i]] = 1;
else
m[nums[i]]++;
}
for(auto it = m.begin();it != m.end();it++)
{
if(it->second > n/2)
return it->first;
}
return -1;
}
};
202.快乐数 投机取巧(设置循环N次跳出),快慢双指针(标准解法):快指针多调用一次getnext()即多跑了一格
class Solution {
public:
bool isHappy(int n) {
int tmp = n;
int cnt = 0;
while(tmp != 1)
{
int sum = 0;
while(tmp != 0)
{
sum += (tmp % 10)*(tmp % 10);
tmp = tmp / 10;
}
tmp = sum;
cnt++;
if(cnt > 1000) return false;
}
return true;
}
};
注意:多调用一次getnext()等于多跑了一格,调用的对象也要注意,快慢指针分别有不同的速度。
class Solution {
public:
int getNext(int n)
{
int sum = 0;
while(n != 0)
{
sum += (n % 10)*(n % 10);
n = n / 10;
}
return sum;
}
bool isHappy(int n) {
int slowR = n;
int fastR = getNext(n);
while(fastR != 1 && slowR != fastR)
{
slowR = getNext(slowR); //慢指针速度针对慢指针对象
fastR = getNext( getNext(fastR));
}
return fastR == 1;//fast跳出时,若不是1则铁定有循环了
}
};
189.旋转数组 环状替代,reverse的妙用(更方便)
环状替代基本思路想出来了,但是没法自己处理n是k的整数倍的问题。题解用了一个外层循环的start指针替代,内层循环回到一次原点则跳出到外层,外层指针加一。
public class Solution {
public:
void rotate(int[] nums, int k) {
k = k % nums.size();
int count = 0;
for (int start = 0; count < nums.length; start++) {
int current = start;
int tmp1 = nums[start];
do {
int next = (current + k) % nums.length;
int tmp2 = nums[next];//把目标位置的值保存
nums[next] = tmp1;//把该放在这个位置的值(来自于上个位置的)放好
tmp1 = tmp2;//把要放置的值更新
current = next;//指针移到下个正确的位置
count++;
} while (start != current);//回一次原点,则原点+1,保证可以遍历所有数组。如果不是n不是k的整数倍,则在内层循环中就搞完了
}
}
}
用reverse做(推荐):
先整体颠倒,然后颠倒前K个,再颠倒剩下的部分,就是结果了。
注意reverse里面的是指针范围是左闭右开的。左边的截取到你写的那个指针,右边的截取到你写的结尾指针的前一个。(就比如说标准的vector的末尾end()指针是指向结尾的那个空指针,闭区间的取值规则正好可以取到最后一个元素)
class Solution {
public:
void rotate(vector<int>& nums, int k) {
k = k% nums.size();
reverse(nums.begin(), nums.end());
reverse(nums.begin(), nums.begin() + k);
reverse(nums.begin() + k , nums.end());
}
};
53.最大自序和 贪心算法
PTA中出现过类似的。遍历一遍的同时算sum,如果sum小于0则直接抛弃,把sum归零。否则一直加下去,用result保存每个出现过的sum里面最大的值。
注意:INT_MIN才是最小的整数,-2147483648;INTMAX_MIN不知道是啥玩意,调试中显示为0;
class Solution {
public:
int maxSubArray(vector<int>& nums) {
int len = nums.size();
int res = INT_MIN;
int sum = 0;
if (nums.size() == 1) return nums[0];
for (int i = 0; i<len; i++)
{
sum += nums[i];
res = max(res, sum);
if (sum < 0)
sum = 0;
}
return res;
}
};
66.加一 insert的用法
vector.insert(加在这个位置的前面,你要加的元素)
或者
void insert(目标位置,你要加的片段的开头,你要加的片段的结尾);
class Solution {
public:
vector<int> plusOne(vector<int>& digits) {
int len = digits.size();
int jin = (digits[len - 1] + 1) < 10 ? 0 : 1;
digits[len - 1] = ( (digits[len - 1] + 1)% 10);
for (int i = len - 2; i >= 0; i--)
{
int tmp = digits[i] + jin;
jin = tmp / 10;
digits[i] = tmp % 10;
}
if (jin == 1)
digits.insert(digits.begin(), 1);
return digits;
}
};
67.二进制求和 str.append(你要补几个,你要补的元素)
PTA中出现过类似题,用颠倒后补全的方法做较优(空间超过100%,时间超过80%)
用到append函数来补0。
class Solution {
public:
string addBinary(string a, string b) {
int lenA = a.length(), lenB = b.length();
reverse(a.begin(), a.end());
reverse(b.begin(), b.end());
if (lenA > lenB)
b.append(lenA - lenB, '0');
else
a.append(lenB - lenA, '0');
int jin = 0;
for (int i = 0; i < a.length(); i++)
{
int sum = (a[i] - '0') + (b[i] - '0') + jin;
a[i] = (sum % 2 + '0');
jin = sum / 2;
}
if (jin == 1)
a.insert(a.end(), '1');
reverse(a.begin(), a.end());
return a;
}
};
58.最后一个单词的长度 字符串处理
从后往前找,从第一个不是空格的字符开始计数,再遇到空格就返回。
class Solution {
public:
int lengthOfLastWord(string s) {
int sum = 0, len = s.length();
int flag = 0;//0为还没开始一个单词,1为开始了
for (int i = len - 1 ; i >= 0; i--)
{
if (!isalpha(s[i]) && flag == 0)
continue;
else if (isalpha(s[i]))
{
flag = 1;
sum++;
}
else if (!isalpha(s[i]) && flag == 1)
return sum;
}
return sum;
}
};
121.买卖股票最佳时机 贪心法,类似前面的最大子列和这题
class Solution {
public:
int maxProfit(vector<int>& prices) {
int result = INT_MIN;
int sum = 0;
for (int i = 1; i < prices.size(); i++)
{
int tmp = prices[i] - prices[i - 1];//单日利润
sum += tmp;//从买入日算起的总和利润
if (sum > 0)
result = max(result, sum);//记录总利润最大值
else
sum = 0;//如果总利润为负了,抛弃之前的买入日,从下一个日子重新开始计算
}
if (result != INT_MIN)
return result;
else
return 0;
}
};
203.移除链表元素 哨兵,指针结点删除与释放。
引入哨兵可以规避空指针的情况特殊情况,头哨兵是一种通用的方法。
删除指针的时候是,如果不删除,才令it = it->next这样移动,不然的话删除的那一次循环是不进行移动的,因为如果移动删除同时进行,删除掉的结点后面的那个结点相当于没做判断了。
class Solution {
public:
ListNode* removeElements(ListNode* head, int val) {
ListNode* dummy = new ListNode(0);//头哨兵
dummy->next = head;
ListNode* it = dummy;
while ( it ->next != NULL)
{
if (it->next->val == val)
{
ListNode* tmp = it->next;
it->next = it->next->next;
delete tmp;
}
else
it = it->next;
}
return dummy->next;
}
};
204.计数质数 IsPrime,厄拉多塞筛法
IsPrime效率低下,用厄拉多塞筛选,由小到大遍历数组。每次排除一个数字的倍数,并改变标记,剩下的数就全是素数了。
注意:vector的初始化方法–vec(你要初始化多少个格子,你要舒适化的数值)
class Solution {
public:
int countPrimes(int n) {
int count = 0;
vector<int> sign(n,0);
for (int i = 2; i < n; i++)
{
if (sign[i] == 0)
{
count++;
for (int j = i + i; j < n; j = j+i)
sign[j] = 1; //排除掉这个数的所有倍数,并改标记
}
}
return count;
}
};
205.同构字符串 hashmap,str.find()
妙用str.find()返回某个字符在str中第一次出现的位置。也就是说如果不同构,必然那轮循环返回的位置不一样。
//方法一:双哈希表做法 时间15%,内存100%
class Solution {
public:
bool isIsomorphic(string s, string t) {
if (s.length() != t.length()) return false;
map<char, char> sign1;
map<char, char> sign2;
for (int i = 0; i < s.length(); i++)
{
if (sign1.find(t[i]) == sign1.end() && sign2.find(s[i]) == sign2.end())//如果没找到
{
sign1[t[i]] = s[i];
sign2[s[i]] = t[i];
}
else
{
if (s[i] != sign1[t[i]] || t[i] != sign2[s[i]])
return false;
}
}
return true;
}
};
//方法二:用str.find()返回特性--返回第一次出现这个字符的位置 时间89%,空间100%
class Solution {
public:
bool isIsomorphic(string s, string t) {
if (s.length() != t.length()) return false;
for (int i = 0; i < s.length(); i++)
{
if (s.find(s[i]) != t.find(t[i]))
return false;
}
return true;
}
};
206.翻转链表 迭代用双指针,递归需要多看多理解记住。
迭代(更好理解且常用):
一前一后俩指针,由于next要断裂,所以需要预先储存好next的指针值。然后再一次挪动俩指针即可。
class Solution {
public:
ListNode* reverseList(ListNode* head) {
ListNode* pre = head;
ListNode* cur = NULL;
while ( pre != NULL)
{
ListNode* tmp = pre->next;
pre->next = cur;
cur = pre;
pre = tmp;
}
return cur;
}
};
递归:
最先直接到12345的第5层(因为5的next就是空了),返回4的层数后,这里面的P就是5这个节点本身。随后用5->next->next也就是5指向4,4指向空(这么做是为了1最后指向空)。然后4由返回3的层数。以此类推知道本身为空结束。
class Solution {
public:
ListNode* reverseList(ListNode* head) {
if (head == NULL || head->next == NULL) {
return head;
}
ListNode* p = reverseList(head->next);
head->next->next = head;
head->next = NULL;
return p;
}
};