返回介绍

solution / 0600-0699 / 0650.2 Keys Keyboard / README

发布于 2024-06-17 01:03:35 字数 5006 浏览 0 评论 0 收藏 0

650. 两个键的键盘

English Version

题目描述

最初记事本上只有一个字符 'A' 。你每次可以对这个记事本进行两种操作:

  • Copy All(复制全部):复制这个记事本中的所有字符(不允许仅复制部分字符)。
  • Paste(粘贴):粘贴 上一次 复制的字符。

给你一个数字 n ,你需要使用最少的操作次数,在记事本上输出 恰好 n 个 'A' 。返回能够打印出 n 个 'A' 的最少操作次数。

 

示例 1:

输入:3
输出:3
解释:
最初, 只有一个字符 'A'。
第 1 步, 使用 Copy All 操作。
第 2 步, 使用 Paste 操作来获得 'AA'。
第 3 步, 使用 Paste 操作来获得 'AAA'。

示例 2:

输入:n = 1
输出:0

 

提示:

  • 1 <= n <= 1000

解法

方法一:记忆化搜索

定义 $dfs(i)$ 为输出 $i$ 个字符的最少操作次数。初始化 dfs(1)=0

当 $i\gt 1$ 时,有:

$$ dfs(i)=\min _{j \mid i} (dfs(\frac{i}{j})+j, i), 2\leq j\lt i $$

时间复杂度 $O(n\sqrt{n})$。

class Solution:
  def minSteps(self, n: int) -> int:
    @cache
    def dfs(n):
      if n == 1:
        return 0
      i, ans = 2, n
      while i * i <= n:
        if n % i == 0:
          ans = min(ans, dfs(n // i) + i)
        i += 1
      return ans

    return dfs(n)
class Solution {
  private int[] f;

  public int minSteps(int n) {
    f = new int[n + 1];
    Arrays.fill(f, -1);
    return dfs(n);
  }

  private int dfs(int n) {
    if (n == 1) {
      return 0;
    }
    if (f[n] != -1) {
      return f[n];
    }
    int ans = n;
    for (int i = 2; i * i <= n; ++i) {
      if (n % i == 0) {
        ans = Math.min(ans, dfs(n / i) + i);
      }
    }
    f[n] = ans;
    return ans;
  }
}
class Solution {
public:
  vector<int> f;

  int minSteps(int n) {
    f.assign(n + 1, -1);
    return dfs(n);
  }

  int dfs(int n) {
    if (n == 1) return 0;
    if (f[n] != -1) return f[n];
    int ans = n;
    for (int i = 2; i * i <= n; ++i) {
      if (n % i == 0) {
        ans = min(ans, dfs(n / i) + i);
      }
    }
    f[n] = ans;
    return ans;
  }
};
func minSteps(n int) int {
  f := make([]int, n+1)
  for i := range f {
    f[i] = -1
  }
  var dfs func(int) int
  dfs = func(n int) int {
    if n == 1 {
      return 0
    }
    if f[n] != -1 {
      return f[n]
    }
    ans := n
    for i := 2; i*i <= n; i++ {
      if n%i == 0 {
        ans = min(ans, dfs(n/i)+i)
      }
    }
    return ans
  }
  return dfs(n)
}

方法二:动态规划

记忆化搜索也可以改成动态规划。

$$ dp[i]=\min _{j \mid i} (dp[\frac{i}{j}]+j, i), 2\leq j\lt i $$

时间复杂度 $O(n\sqrt{n})$。

class Solution:
  def minSteps(self, n: int) -> int:
    dp = list(range(n + 1))
    dp[1] = 0
    for i in range(2, n + 1):
      j = 2
      while j * j <= i:
        if i % j == 0:
          dp[i] = min(dp[i], dp[i // j] + j)
        j += 1
    return dp[-1]
class Solution {
  public int minSteps(int n) {
    int[] dp = new int[n + 1];
    for (int i = 0; i < n + 1; ++i) {
      dp[i] = i;
    }
    dp[1] = 0;
    for (int i = 2; i < n + 1; ++i) {
      for (int j = 2; j * j <= i; ++j) {
        if (i % j == 0) {
          dp[i] = Math.min(dp[i], dp[i / j] + j);
        }
      }
    }
    return dp[n];
  }
}
class Solution {
public:
  int minSteps(int n) {
    vector<int> dp(n + 1);
    iota(dp.begin(), dp.end(), 0);
    dp[1] = 0;
    for (int i = 2; i < n + 1; ++i) {
      for (int j = 2; j * j <= i; ++j) {
        if (i % j == 0) {
          dp[i] = min(dp[i], dp[i / j] + j);
        }
      }
    }
    return dp[n];
  }
};
func minSteps(n int) int {
  dp := make([]int, n+1)
  for i := range dp {
    dp[i] = i
  }
  dp[1] = 0
  for i := 2; i < n+1; i++ {
    for j := 2; j*j <= i; j++ {
      if i%j == 0 {
        dp[i] = min(dp[i], dp[i/j]+j)
      }
    }
  }
  return dp[n]
}

方法三

class Solution {
  public int minSteps(int n) {
    int res = 0;
    for (int i = 2; n > 1; ++i) {
      while (n % i == 0) {
        res += i;
        n /= i;
      }
    }
    return res;
  }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文