Skip to content

1871. Jump Game VII#68

Open
kitano-kazuki wants to merge 1 commit into
mainfrom
1871-jump-game-7
Open

1871. Jump Game VII#68
kitano-kazuki wants to merge 1 commit into
mainfrom
1871-jump-game-7

Conversation

@kitano-kazuki
Copy link
Copy Markdown
Owner

Comment thread memo.md
@@ -1 +1,91 @@
# Step1

## Code1-1
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

自分でも解いてみまし。シンプルな解法が思いつかず、 range query を平方分割で実装して解きました。初めは Binary Indexed Tree を二次元配列で書き始めたのですが、更新部分が上手く書けず、平方分割に逃げました。
供養のために貼っておきます。

class Solution {
public:
    bool canReach(string s, int minJump, int maxJump) {
        if (s[s.size() - 1] != '0') {
            return false;
        }

        vector<int8_t> reached(BASE * BASE);
        vector<int> reached_sqrt_count(BASE);
        set(reached, reached_sqrt_count, 0, 1);

        for (int i = 0; i < s.size(); ++i) {
            if (s[i] != '0') {
                continue;
            }

            if (!get(reached, reached_sqrt_count, i)) {
                continue;
            }

            set(reached, reached_sqrt_count, i + minJump, min(i + maxJump, (int)s.size() - 1) + 1);
        }

        return get(reached, reached_sqrt_count, s.size() - 1);
    }

    void set(vector<int8_t>& reached, vector<int>& reached_sqrt_count, int begin, int end) {
        int left = (begin + BASE - 1) / BASE * BASE;
        int right = end / BASE * BASE;
        for (int bucket = left / BASE; bucket < right / BASE; ++bucket) {
            reached_sqrt_count[bucket] = BASE;
        }

        if (begin / BASE == end / BASE) {
            for (int i = begin; i < end; ++i) {
                set(reached, reached_sqrt_count, i);
            }
        } else {
            for (int i = begin; i < left; ++i) {
                set(reached, reached_sqrt_count, i);
            }

            for (int i = right; i < end; ++i) {
                set(reached, reached_sqrt_count, i);
            }
        }
    }

    void set(vector<int8_t>& reached, vector<int>& reached_sqrt_count, int i) {
        if (reached[i]) {
            return;
        }
        reached[i] = true;
        ++reached_sqrt_count[i / BASE];
    }

    bool get(const vector<int8_t>& reached, const vector<int>& reached_sqrt_count, int index) {
        return reached_sqrt_count[index / BASE] == BASE ||
            reached[index];
    }

private:
    static constexpr const int BASE = 1000;
};

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

reached_sqrt_count[i]はバケットiのうち到達可能な個数を表しているのですか?

        for (int bucket = left / BASE; bucket < right / BASE; ++bucket) {
            reached_sqrt_count[bucket] = BASE;
        }

この部分の更新は, バケット内すべてを到達可能とみなしているように思いましたが、バケット内のインデックスjでs[j]=1なるjに対しても, 到達可能としていることになりませんか?

Copy link
Copy Markdown

@nodchip nodchip May 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

その理解であっているように思います。

本来やりたいことは reached の [begin, end) の範囲を true にすることです。一方、これには O(N) かかります。これを避けるため、 reached を sqrt(reached.size()) 個のバケットに分け、 reached の [left, right) の範囲を true とする代わりに、対応する reached_sqrt_count を BASE に設定しています。これによりO(sqrt(N)) になります。
また、 get() する際に、 reached_sqrt_count が BASE となっている、つまりバケット内のすべての reached が true となっているか、 reached[index] のどちらがが true となっていれば、 true を返すようにしています。

ただ、 set() が間違っていることに気づきました。正しくは以下の通りです。

    void set(vector<int8_t>& reached, vector<int>& reached_sqrt_count, int i) {
        if (get(reached, reached_sqrt_count, i)) {
            return;
        }
        reached[i] = true;
        ++reached_sqrt_count[i / BASE];
    }

元のコードでも Accepted してしまっていました。 LeetCode のテストケースが弱かったためだと思います。

なお、平方分割はソフトウェアエンジニアの常識には含まれていないと思います。

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

理解できました。平方分割は自分もよくわからなくて調べながら理解したのですが、解法として浮かんでいなかったので勉強になりました。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants