zoukankan      html  css  js  c++  java
  • 打败算法 —— 圆圈中最后剩下的数字

    本文参考

    出自LeetCode上的题库 —— 圆圈中最后剩下的数字,乍看这道题用循环链表解决,奈何输入的数值太大,程序不是超出内存限制就是超出时间限制,力扣上已经有大大通过数学公式解决了这道题,不过很不服气的我还是尝试了好几次循环链表(没成功_(:D)∠)_)

    https://leetcode-cn.com/problems/yuan-quan-zhong-zui-hou-sheng-xia-de-shu-zi-lcof/

    圆圈中最后剩下的数字问题

    0,1,,n-1这n个数字排成一个圆圈,从数字0开始,每次从这个圆圈里删除第m个数字。求出这个圆圈里剩下的最后一个数字。例如,0、1、2、3、4这5个数字组成一个圆圈,从数字0开始每次删除第3个数字,则删除的前4个数字是2、0、4、1,因此最后剩下的数字是3。

    示例 1:
    输入: n = 5, m = 3
    输出: 3

    示例 2:
    输入: n = 10, m = 17
    输出: 2

    限制:
    1 <= n <= 10^5
    1 <= m <= 10^6

    解题思路

    甜姨(@Sweetiee)在题解中提了一下下,LinkedList删除一个节点的时间复杂度为O(1),但是要找到对应的节点需要一个个遍历,时间复杂度为O(n),而使用ArrayList勉强可以不超时,虽然ArrayList查找一个节点的时间复杂度为O(1),删除一个节点的时间复杂度为O(n),但是因为删除节点时,后继节点的前移是连续内存空间的拷贝,效率会比LinkedList快

    不过我想,我们可以提高链表的查询效率呀!通过双向循环链表,一定程度上可以减少要查找的节点个数

    我们可以用一个整型记录当前结点的数量,这个值还可以作为跳出while循环的条件。当移动的步长大于当前节点的数量时,可以对移动次数进行缩减,去掉冗余的"转圈圈"次数,经过测试还是不够快,测试数值在50000+节点数量时就报了超时错误。所以节点不能只是单纯的向前移动,如果要删除的点更偏向于当前节点的前部,那么应当向前移动,这也是设计成双向的原因。

    即便如此仍然没能打败70000+的测试数值,双向循环链表在执行70000+节点数量时,大概需要2 ~ 4秒的时间(欲哭无泪)

    双向循环链表算法

    // 内部类
    private class Node {
      private int nodeValue; //
    当前节点值
      private Node nextNode; // 下一个节点
      private Node preNode; // 前一个节点

      public Node(int nodeValue) {
        this.nodeValue = nodeValue;
        this.nextNode = null;
        this.preNode = null;
      }
    }

    public int lastRemaining(int n, int m) {
      if (m == 1) {
        return n - 1;
      }

      //
    构造双向循环链表
      Node root = new Node(0);
      Node tail = root, preNode;
      for (int i = 1; i < n; i++) {
        preNode = tail;
        Node newNode = new Node(i);
        tail.nextNode = newNode;
        tail = newNode;
        tail.preNode = preNode;
      }

      tail.nextNode = root;
      root.preNode = tail;

      Node currNode = root;
      int nodeNum = n;
      while (nodeNum != 1) {
        //
    去掉"转圈圈"的冗余次数
        int moveTimes;
        if (m < nodeNum) {
          moveTimes = m - 1;
        } else if (m % nodeNum == 0) {
          moveTimes = nodeNum - 1;
        } else {
          moveTimes = m % nodeNum - 1;
        }

        //
    决定向前还是向后移动
        if (moveTimes > nodeNum / 2) {
          for (int i = 1; i <= nodeNum - moveTimes; i ++) {
            currNode = currNode.preNode;
          }
        } else {
          for (int i = 1; i <= moveTimes; i++) {
            currNode = currNode.nextNode;
          }
        }

        //
    删除节点
        Node tmp = currNode.preNode;
        tmp.nextNode = currNode.nextNode;
        currNode = currNode.nextNode;
        currNode.preNode = tmp;
        nodeNum--;
        }
      return currNode.nodeValue;
    }

    测试用例:

    71989, 111059

    输出:

    34203(耗时2 ~ 4秒)

  • 相关阅读:
    asp.net发布到IIS中出现错误:处理程序“PageHandlerFactory-Integrated”在其模块列表中有一个错误模块“ManagedPipelineHandler”
    System.Core, Version=2.0.5.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e, Retargetable=Yes”
    禁止tableview 像上滑动
    IOS 贝塞尔曲线切割圆角
    头像图片裁剪
    iOS 限制TextField输入长度
    根据经纬度反向地理编译出地址信息(如果报错:Error Domain=kCLErrorDomain Code=8 "(null)")
    空白页界面
    NSPhotoLibraryAddUsageDescription解决办法
    IOS字符串截取保留小数点后两位
  • 原文地址:https://www.cnblogs.com/kuluo/p/12600898.html
Copyright © 2011-2022 走看看