约瑟夫环
- 递归
- f(n, m) 表示从n个数中每次删除第m个, 最后剩下的值的下标 (注意m是第m个, f是下标, m-1=f的)
- f(n, m) = (((f(n-1, m) + 1) + m%n ) - 1) % n = (f(n-1, m) + m) % n;
- f(n-1, m) + 1 是第几个, 也就是偏移量, f(n-1, m) + 1 + m%n 就是最终答案的偏移量, 求下标时应该-1取模, 最后化简就是(f(n-1, m) + m) % n;
- 循环数组中, ( 偏移量 - 1 ) % 长度 = 下标
- 迭代
- 递归是自顶向下, 迭代是自底向上
- 因为递归中每次结果只与f(n-1, m)有关, 因此可以从f(1, m)开始一直算到f(n, m), 每次只记录前一个的值
class Solution {
public:
int lastRemaining(int n, int m) {
// if(n == 1) return 0;
// int x = lastRemaining(n-1, m);
// return (m + x) % n;
int x = 0;
for(int i = 2; i <= n; i++)
{
x = (x + m) % i;
}
return x;
}
};
链表拷贝
// 两种深度复制方式
// 两条线, 新链表和原链表的指针同时行进. 最后原链表的头指针指向了最后
Node* new_head = NULL;
if(head == NULL)
return new_head;
new_head = new Node(head->val);
Node* node = new_head;
head = head->next;
while(head != NULL)
{
Node* temp = new Node(head->val);
node->next = temp;
node = node->next;
head=head->next;
}
return new_head;
// 一条线, 只要next不为空, 就把next复制一个, 进行替换. 最后原链表头指针没动
Node* new_head = NULL;
if(head == NULL)
return new_head;
new_head = new Node(head->val);
new_head->next = head->next;
Node* node = new_head;
while(node->next != NULL)
{
Node* temp = new Node(node->next->val);
temp->next = node->next->next;
node->next = temp;
node = node->next;
}
return new_head;
递归
Node* dfs(Node* head,map<Node*, Node*>& mp)
{
if(head == NULL) return NULL;
Node* new_head = new Node(head->val);
mp[head] = new_head;
new_head->next = dfs(head->next, mp);
return new_head;
}
数组中数字出现的次数
一个整型数组 nums 里除两个数字之外,其他数字都出现了两次。请写程序找出这两个只出现一次的数字。要求时间复杂度是O(n),空间复杂度是O(1)。
- 所有数字进行异或操作, 出现两次的数字, 在每一位上由于是相同, 异或得0. 最后的结果就是两个不同的数进行异或的结果.
想办法根据这个结果将两者分开
- 异或结果中0位, 表示该位上两者相同; 1位表示改位上两者不等.
- 找到一个1位, 将这个位上为0的数放在一组, 为1的数放在一组. 这样出现两次的数仍然在同一组, 但是出现一次的两个数就被分到了两个组.
- 两个组分别进行所有数字的异或, 最后答案分别得到那两个数字.
x^1 = ~x , x^0 = x, ~x+1 = -x
class Solution {
public:
vector<int> singleNumbers(vector<int>& nums) {
int ret = 0;
for(auto& val : nums)
ret ^= val;
int div = 1;
while((ret&div)==0)
div = div<<1;
int a = 0, b = 0;
for(auto& val : nums)
if (val & div)
a ^= val;
else
b ^= val;
return {a,b};
}
};
礼物的最大价值
BFS、DFS、DP、DP空间优化
- BFS 和 DFS 会超时, 但是是很好的模版框架
class Solution {
public:
struct Point
{
int x;
int y;
int val;
};
vector<pair<int, int>> directions = {{0, 1},{1, 0}};
int res = INT_MIN;
/*
void bfs(vector<vector<int>>& grid, int m, int n, int i, int j, int sum)
{
queue<Point> q;
q.push({i, j, sum});
while(!q.empty())
{
Point temp = q.front();
q.pop();
// 终止条件
if (temp.x == m-1 && temp.y == n-1)
{
res = max(res, temp.val);
}
// 遍历
for(auto& dir : directions)
{
int newi = temp.x + dir.first;
int newj = temp.y + dir.second;
if(newi >= 0 && newi < m && newj >= 0 && newj < n)
{
int newsum = temp.val + grid[newi][newj];
q.push({newi, newj, newsum});
}
}
}
}
*/
/*
void dfs(vector<vector<int>>& grid, int m, int n, int i, int j, int sum)
{
if(i == m-1 && j == n-1)
{
res = max(res, sum);
return ;
}
for(auto& p : directions)
{
int newi = i + p.first;
int newj = j + p.second;
if(newi >= 0 && newi < m && newj >= 0 && newj < n)
{
sum += grid[newi][newj];
dfs(grid, m, n, newi, newj, sum);
sum -= grid[newi][newj];
}
}
}
*/
/*
int dp_f(vector<vector<int>>& grid, int m, int n)
{
vector<vector<int>> dp(m, vector<int>(n,0));
for(int i = 0; i < m; i++)
{
for(int j = 0; j < n; j++)
{
if(i>=1 && j >= 1)
dp[i][j] = max(dp[i][j-1] + grid[i][j], dp[i-1][j] + grid[i][j]);
else if (i >= 1)
dp[i][j] = dp[i-1][j] + grid[i][j];
else if (j >= 1)
dp[i][j] = dp[i][j-1] + grid[i][j];
else
dp[0][0] = grid[0][0];
}
}
return dp[m-1][n-1];
}
*/
// 空间优化
int dp_youhua(vector<vector<int>>& grid, int m, int n)
{
for(int i = 0; i < m; i++)
{
for(int j = 0; j < n; j++)
{
if(i>=1 && j >= 1)
grid[i][j] = max(grid[i][j-1] + grid[i][j], grid[i-1][j] + grid[i][j]);
else if (i >= 1)
grid[i][j] = grid[i-1][j] + grid[i][j];
else if (j >= 1)
grid[i][j] = grid[i][j-1] + grid[i][j];
else
continue;
}
}
return grid[m-1][n-1];
}
int maxValue(vector<vector<int>>& grid) {
int m = grid.size();
int n = grid[0].size();
// int sum = grid[0][0];
// bfs(grid, m, n, 0, 0, sum);
return dp_youhua(grid, m, n);
}
};