约瑟夫环、链表拷贝、数组中数字出现的次数、礼物的最大价值

约瑟夫环

  • 递归
    • 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);
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值