.
- 树状数组
- lc 307. 区域和检索 - 数组可修改
- n数之和问题
- 三数之和 四数字之和
- 位运算
- lc 371. 两整数之和
- 构造
- lc 667. 优美的排列 II
- 字符串
- 【字符串拼接】lc 273. 整数转换英文表示
- dp
- 【最长上升子序列】华为机试 HJ103 Redraiment的走法
- 最长回文子串
- HJ85 最长回文子串【字符串预处理】
树状数组
lc 307. 区域和检索 - 数组可修改
class NumArray {
public:
vector<int> a;
vector<int> c;
int n=0;
int low(int i){
return i&(-i);
}
NumArray(vector<int>& nums) {
a = std::move(nums);
n = a.size();
c = vector<int>(a.size()+1,0);
for(int i=1;i<=n;++i){
updatec(i,a[i-1]);
}
}
void updatec(int i, int val) {
for(;i<=n; i += low(i)){
c[i]+= val;
}
}
void update(int i, int val) {
updatec(i+1,val-a[i]);
a[i]=val;
}
int getsum(int r){
int ret =0;
for(;r>=1;r -= low(r)){
ret+=c[r];
}
return ret;
}
int sumRange(int left, int right) {
return getsum(right+1) - getsum(left);
}
};
n数之和问题
位运算
lc 371. 两整数之和
class Solution {
public:
int getSum(int a, int b) {
int axorb = (a^b);
int aandb = (unsigned int)(a&b)<<1;
while(aandb){
auto jin = (unsigned int)(aandb & axorb) << 1;
axorb ^= aandb;
aandb = jin;
}
return axorb;
}
};
可以看做是一个递归的过程
LeetCode不允许超过int赋值,但是unsigned int 超过范围,直接做了截断
我在vs调试的时候 不用(unsigned int)也是可以的
a+b可以看做是两个部分的加法
1. a^b 无进位加法
2. (a&b)<<1 需要加上的进位
计算 a^b + ((a&b)<<1)
计算不进位的很容易,直接异或就行了
加上进位的时候,其实这个问题,就是原问题,
只不过a+b,只不过此时的b最后一位是0
可以看做是一种问题规模的缩小,因为当b全是0的时候,a就是答案了
所以递归的版本也比较容易理解了
需要注意的是统一符号,负数的加法,符号位应该怎么确定呢?
以3个二进制位举例(第一位是符号位)
-3 | -2 | -1 | -0 | 0 | 1 | 2 | 3 | |
原码 | 111 | 110 | 101 | 100 | 000 | 001 | 010 | 011 |
反码 | 100 | 101 | 110 | 111 | 000 | 001 | 010 | 011 |
补码 | 101 | 110 | 111 | 100 | 000 | 001 | 010 | 011 |
100 | 101 | 110 | 111 |
| 000 | 001 | 010 | 011 |
按照二进制加法,
使用原码 在-3+1!= -2
从反码中可以看到
-3+1 = -2,实现了负数范围内二进制加法和正数的统一
但是有两个0的,就会出现问题,-1+1=-0 然后-1+2 = +0
此时3+1 = -3
这显然不是我们想要的
所以将负数的反码进行一个修正,就是整体向右移动一位
这样一来-1修正之后的码就和(-0)的反码一样,-1+1 = +0
从而-1和+0就连续了,这个修正之后也就是补码
但是之前的-0似乎没用了,就可以用来表示-4,
此时3+1 = -4
查看二进制
template<class T>
void printBinary(const T& x) {
int n = (sizeof x) * 8;
char* s = (char*)&x;
cout << x << "\t: ";
for (int i = n - 1; i >= 0; --i) {
int a = i / 8, b = i % 8;
if ((s[a]) & (1 << b))printf("1");
else printf("0");
if (b == 0)printf(" ");
}
cout << endl;
}
构造
lc 667. 优美的排列 II
使用前k+1个数字就可以构造出k个不同的数,后面的直接放进去就行
以n=10,k=4为例
从1开始 +4 -3 +2 -1 后面的直接填上去就行
1 5 2 4 3 6 7 8 9 10
class Solution {
public:
vector<int> constructArray(int n, int k) {
vector<int> ret = {1};
int c = 1;
for (int i = k; i >= 1; --i) {
if (ret.size() % 2 == 1) {
c += i;
}
else {
c -= i;
}
ret.push_back(c);
}
c = k + 1;
while (ret.size()<n) {
++c;
ret.push_back(c);
}
return ret;
}
};
字符串
【字符串拼接】lc 273. 整数转换英文表示
class Solution {
public:
unordered_map<int, string> m = {
{1, "One"},
{2, "Two"},
{3, "Three"},
{4, "Four"},
{5, "Five"},
{6, "Six"},
{7, "Seven"},
{8, "Eight"},
{9, "Nine"},
{10, "Ten"},
{11, "Eleven"},
{12, "Twelve"},
{13, "Thirteen"},
{14, "Fourteen"},
{15, "Fifteen"},
{16, "Sixteen"},
{17, "Seventeen"},
{18, "Eighteen"},
{19, "Nineteen"},
{20, "Twenty"},
{30, "Thirty"},
{40, "Forty"},
{50, "Fifty"},
{60, "Sixty"},
{70, "Seventy"},
{80, "Eighty"},
{90, "Ninety"},
};
int Billion = 1000000000;
int Million = 1000000;
int Thousand = 1000;
int Hundred = 100;
string int_str(int a) {
stringstream ss;
ss << a;
return ss.str();
}
string help(int n) {
string ret = "";
if(n==0) return "Zero ";
if (n >= Billion) {
ret += help(n / Billion) + "Billion ";
n -= n / Billion * Billion;
}
if (n >= Million) {
ret += help(n / Million) + "Million ";;
n -= n / Million * Million;
}
if (n >= Thousand) {
ret += help(n / Thousand) + "Thousand ";
n -= n / Thousand * Thousand;
}
if (n >= Hundred) {
ret += help(n / Hundred) + "Hundred ";
n -= n / Hundred * Hundred;
}
if (n >= 20) {
ret += m[n / 10 * 10] + " ";
n -= n / 10 * 10;
}
if (n >= 1) {
ret += m[n] + " ";
}
return ret;
}
string numberToWords(int n) {
auto s = help(n);
return s.substr(0, s.size() - 1);
}
};
dp
【最长上升子序列】华为机试 HJ103 Redraiment的走法
#include <iostream>
#include <vector>
using namespace std;
int n;
void f(){
auto a = vector<int>(n,0);
for(int i=0;i<n;++i){
cin>>a[i];
}
auto dp = vector<int>(n,1);
int ret = 1;
for(int i=1;i<n;++i){
for(int j=0;j<i;++j){
if( a[i]>a[j] ){
dp[i] = max(dp[i],dp[j]+1);
ret = max(ret,dp[i]);
}
}
}
cout<<ret<<endl;
}
int main(){
while(cin>>n)
f();
return 0;
}
最长回文子串
HJ85 最长回文子串【字符串预处理】
#include <iostream>
using namespace std;
#define debug(x) cout<<#x<<": "<<(x)<<endl;
int main(){
string s;
cin>>s;
string sc = "#";
for(auto c:s){
sc += c;
sc += "#";
}
//debug(sc);
int n = sc.size();
int ret=0;
for(int i=0;i<n;++i){
int j=0;
while(i+j<n && i-j>=0){
if(sc[i-j] != sc[i+j]){
break;
}
++j;
}
ret = max(ret,j);
}
cout<<ret-1<<endl;
return 0;
}