LeetCode 1425. 带限制的子序列和

题目链接:https://leetcode-cn.com/problems/constrained-subsequence-sum/

提议:
在这里插入图片描述

思路:动态规划 dp[i] = Max(nums[i], nums[i] + dp[i + j]) 其中0 < j <= k,但是直接遍历dp[i + j]会超时,所以要维护一个能快速查找dp[i + j]中最大值的结构,可以使用单调栈,也可以用平衡二叉树,由于C#中没有双向队列,干脆就直接拷个Splay树过来。

        public class Solution {

            class SplayTree {
                public SplayNode Root;
                public class SplayNode {
                    //结点为根的子树中总共有多少个结点
                    public int Size;
                    //当前结点有多少个Value
                    public int Count;
                    //当前结点的值
                    public long Value;
                    //父结点
                    public SplayNode Pre;
                    //左右子结点
                    public SplayNode[] Childs = new SplayNode[2];
                    public SplayNode(long _value, SplayNode _pre, SplayNode left = null, SplayNode right = null) {
                        Size = 1;
                        Count = 1;
                        Value = _value;
                        Pre = _pre;
                        Childs[0] = left;
                        Childs[1] = right;
                    }
                }
                public SplayTree() {
                    //创建两个边界结点
                    Root = new SplayNode(long.MinValue, null);
                    Root.Childs[1] = new SplayNode(long.MaxValue, Root);
                    PushUp(Root);
                }

                /// <summary>
                /// 返回子节点方向
                /// </summary>
                /// <param name="rw"></param>
                /// <returns>rw是父结点的左儿子返回0,右儿子返回1</returns>
                public int F(SplayNode rw) {
                    if (rw.Pre.Childs[0] == rw) {
                        return 0;
                    }
                    return 1;
                }

                /// <summary>
                /// 向上更新状态
                /// </summary>
                public void PushUp(SplayNode rt) {
                    rt.Size = rt.Count;
                    for (int i = 0; i < 2; i++) {
                        if (null != rt.Childs[i]) {
                            rt.Childs[i].Pre = rt;
                            rt.Size += rt.Childs[i].Size;
                        }
                    }
                }

                //将rw旋转到父结点的位置
                public void Rotate(SplayNode rw) {
                    int chd = F(rw);
                    SplayNode preNode = rw.Pre;

                    rw.Pre = preNode.Pre;
                    if (null != preNode.Pre) {
                        preNode.Pre.Childs[F(preNode)] = rw;
                    }
                    preNode.Childs[chd] = rw.Childs[1 - chd];
                    rw.Childs[1 - chd] = preNode;

                    PushUp(preNode);
                    PushUp(rw);
                }


                /// <summary>
                /// 调整SplayTree, 将rw调整到rt的子结点
                /// </summary>
                /// <returns></returns>
                public SplayNode Splay(SplayNode rt, SplayNode rw) {
                    while (rw.Pre != rt) {
                        SplayNode preNode = rw.Pre;
                        if (rt == preNode.Pre || F(rw) != F(preNode)) {
                            Rotate(rw);
                        } else {
                            Rotate(preNode);
                            Rotate(rw);
                        }
                    }
                    if (null != rt) {
                        PushUp(rt);
                    } else {
                        Root = rw;
                    }
                    return rw;
                }

                /// <summary>
                /// 插入结点
                /// </summary>
                /// <param name="value"></param>
                /// <returns></returns>
                public SplayNode Insert(long value) {
                    SplayNode curNode = Root;
                    SplayNode newNode = new SplayNode(value, null);
                    while (true) {
                        curNode.Size++;
                        int nextChd = 0;
                        if (value == curNode.Value) {
                            newNode = curNode;
                            newNode.Count++;
                            break;
                        } else if (value < curNode.Value) {
                            nextChd = 0;
                        } else {
                            nextChd = 1;
                        }
                        if (null == curNode.Childs[nextChd]) {
                            newNode.Pre = curNode;
                            curNode.Childs[nextChd] = newNode;
                            break;
                        }
                        curNode = curNode.Childs[nextChd];
                    }
                    return newNode;
                }


                /// <summary>
                /// 删除结点
                /// </summary>
                /// <param name="value"></param>
                /// <returns></returns>
                public bool Delete(long value) {
                    SplayNode node = FindRange(value, value);
                    if (null == node) {
                        return false;
                    }
                    node.Count--;
                    node.Size--;
                    if (node.Count <= 0) {
                        //删除结点
                        node.Pre.Childs[F(node)] = null;
                    }
                    //减小size
                    SplayNode curNode = node;
                    while (null != curNode.Pre) {
                        curNode = curNode.Pre;
                        PushUp(curNode);
                    }
                    return true;
                }

                /// <summary>
                /// 返回小于value的最大的Node
                /// </summary>
                /// <param name="value"></param>
                /// <returns></returns>
                public SplayNode FindNode1(long value) {
                    SplayNode retNode = null;
                    SplayNode curNode = Root;
                    while (null != curNode) {
                        if (value <= curNode.Value) {
                            curNode = curNode.Childs[0];
                        } else {
                            if (null != curNode && (null == retNode || retNode.Value < curNode.Value)) {
                                retNode = curNode;
                            }
                            curNode = curNode.Childs[1];
                        }
                    }
                    return retNode;
                }

                /// <summary>
                /// 返回大于value的最小的Node
                /// </summary>
                /// <param name="value"></param>
                /// <returns></returns>
                public SplayNode FindNode2(long value) {
                    SplayNode retNode = null;
                    SplayNode curNode = Root;
                    while (null != curNode) {
                        if (value < curNode.Value) {
                            if (null != curNode && (null == retNode || curNode.Value < retNode.Value)) {
                                retNode = curNode;
                            }
                            curNode = curNode.Childs[0];
                        } else {
                            curNode = curNode.Childs[1];
                        }
                    }
                    return retNode;
                }


                /// <summary>
                /// 将区间内所有结点放到一个子树上,并返回子树根结点
                /// </summary>
                /// <param name="min"></param>
                /// <param name="max"></param>
                /// <returns></returns>
                public SplayNode FindRange(long min, long max) {
                    SplayNode minNode = FindNode1(min);
                    SplayNode maxNode = FindNode2(max);
                    //minNode旋转到Root
                    Splay(null, minNode);
                    //maxNode旋转为Root右子结点
                    Splay(minNode, maxNode);
                    return maxNode.Childs[0];
                }
            }

            int[] DP = new int[100005];

            public int ConstrainedSubsetSum(int[] nums, int k) {
                SplayTree tree = new SplayTree();
                for (int i = nums.Length - 1; 0 <= i; i--) {
                    DP[i] = nums[i];
                    if (i + k + 1 < nums.Length) {
                        //删除旧结点
                        tree.Delete(DP[i + k + 1]);
                    }
                    var node = tree.FindNode1(long.MaxValue);
                    DP[i] = (int)Math.Max(DP[i], node.Value + nums[i]);
                    //插入新结点
                    tree.Splay(null, tree.Insert(DP[i]));
                }
                int result = DP[0];
                for (int i = 1; i < nums.Length; i++) {
                    result = Math.Max(result, DP[i]);
                }
                return result;
            }
        }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

achonor

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值