[算法题:如何让随机点亮的循环排列的100盏灯全部点亮]

本题来源于一算法同学的面试题

第一想到使用数组,因为存在循环排列,觉得构造循环链表更不错,写完感觉可能还是使用数组简洁些

/**
 * liyang 2021-06-19
 * 算法题:一个圆环上有100个灯泡,灯泡有打开和关闭两种状态,灯泡的状态随机,
 * 按一个灯泡的开关,相邻的两个灯泡的状态也发生一次变化。
 * 比如暗-亮-暗,按中间灯泡,变化为亮-暗-亮。问设计一道算法,使得所有灯泡最后都亮。
 */
struct Node {
    int state;
    Node* next = nullptr;
    Node() {}
    Node(int state) {
        this->state = state;
    }
};

static Node * head = nullptr;
static Node * tail = nullptr;

static Node * lastNodeOff = nullptr;

class LightGame {
public:
    void static lightAllOn() {
        generateLightWithRandomState();

        /**
         * step1
         * 贪心策略,尽可能的让灯变亮
         * 如果灯可以全部变量,这就是我们想要的答案
         * 如果灯不能全部亮进入step2
         */
        greedyWithLightOn();
        if (lastNodeOff == nullptr) {
            cout << "let all light with state on - step1" << endl;
            printAllLightState(head);
            return;
        } else {
            cout << "after step1" << endl;
            printAllLightState(head);
        }

        /**
         * step2
         * 贪心策略,让所有的灯全灭
         * 以 lastNodeOff 当作本轮循环的第一个位置,后面 3 个 1 组,将中间的灯熄灭
         */
        greedyWithLightOff();
        cout << "let all light with state off - step2" << endl;
        printAllLightState(head);

        /**
         * step3
         * 懒惰策略,每个开关按一遍
         * 至此,所有的灯都将变量
         */
//         simpleLazy();
        complexLazy();
        cout << "let all light with state off - step3" << endl;
        printAllLightState(head);

    }
private:
    static void complexLazy() {
        Node* pre = tail;
        Node* node = head;
        for (int i = 0; i < 100; ++i) {
            pre->state ^= 1;
            node->state ^= 1;
            node->next->state ^= 1;
            pre = node;
            node = node->next;
        }
    }

    static void simpleLazy() {
        Node* node = head;
        for (int i = 0; i < 100; ++i) {
            node->state = 1;
        }
    }

    static void greedyWithLightOff() {
        tail->next = head;
        Node* node = lastNodeOff->next;
        for (int i = 1; i <= 99; ++i) {
            node->state = 0;
            node = node->next;
        }
    }

    static void greedyWithLightOn() {
        Node* node = head;
        while (node->next) {
            if (node->state == 0) {
                if (node->next->next) {
                    node->state = 1;
                    node->next->state ^= 1;
                    node->next->next->state ^= 1;
                } else {
                    if (node->next->state == 0) {
                        node->state = node->next->state = 1;
                        head->state = 0;
                        lastNodeOff = head;
                    } else {
                        lastNodeOff = node;
                    }
                }
            }
            node = node->next;
        }
        if (lastNodeOff != nullptr && lastNodeOff->state == 1) {
            lastNodeOff = nullptr;
        }
        if (node->state == 0) {
            lastNodeOff = node;
        }
    }

    /**
     * state => 0 -> OFF  1 -> ON
     */
    void static generateLightWithRandomState() {
        srand((unsigned)time(NULL));
        head = new Node(rand() % 10 > 5 ? 1 : 0);
        Node* node = head;
        for (int i = 1; i < 100; ++i) {
            node->next = new Node(rand() % 10 > 5 ? 1 : 0);
            node = node->next;
        }
        tail = node;
        cout << "generateLightWithRandomState" << endl;
        printAllLightState(head);
    }

    void static printAllLightState(Node* node) {
        int count = 0;
        while (count < 100) {
            ++count;
            cout << node->state << " ";
            node = node->next;
            if (count % 10 == 0) {
                cout << endl;
            }
        }
        cout << endl;
    }
};

int main() {
    LightGame::lightAllOn();
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值