[力扣]只有两个键的键盘

题目:

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

Copy All (复制全部) : 你可以复制这个记事本中的所有字符(部分的复制是不允许的)。
Paste (粘贴) : 你可以粘贴你上一次复制的字符。
给定一个数字 n 。你需要使用最少的操作次数,在记事本中打印出恰好 n 个 'A'。输出能够打印出 n 个 'A' 的最少操作次数。

示例 1:

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

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/2-keys-keyboard

动态规划: 

通过示例一,我们发现如果打印3个字符,我们只能复制,并粘贴2次,所以进行了三个操作;

如果我们想要得到6个字符呢?最初只有一个,我们可以复制,并粘贴两次,这时有3个A,我们在复制,并粘贴的时候就可以得到6个A了;相比于一直复制一次我们步骤少了;

我们还可以复制,粘贴一次,这是有2个A,在复制粘贴两次,得到6个A;

所以我们发现如果想要得到合数(在大于1的整数中,除了1和这个数本身,还能被其他正整数整除的数)个字符时,可以通过复制因数子串,快速得到; 

所以呢?我们可以使用动态规划的方式;

dp[i]  表示我们想要得到i个A需要最少进行dp[i]次操作

最大的步骤就是我们仅复制一次,一直粘贴知道获得i个A;即我们可以将dp[i]初始化为i

i%n==0    dp[i]=min(dp[i],dp[n]+i/n);

 int minSteps(int n) {
        if(n<=1)
          return 0;
        vector<int> dp(n+1,0);
        for(int i=2;i<=n;++i)
        {
            dp[i]=i;
            for(int j=2;j<i;++j)
            {
                if(i%j==0)
                {
                    dp[i]=min(dp[i],dp[j]+i/j);
                }
            }
        }
        return dp[n];
    }

上面的方法可以解决这个问题,但是效率实在是不怎么样

我们也可以算一下,时间复杂度O(n^2);空间复杂度O(n)

当然还有更高效的方法,就是官方解素数分解;

素数分解:

这种方法的思路是这个样子的,倘若N是一个合数,恰好P*Q=N;倘若我们将N个A分成两组 第一组为P个,第二组为Q个;第一组呢?可以是通过一次复制P-1次粘贴得到,第二组可是如果一个复制Q-1次粘贴;当P>=2&&Q>=2的时候 (P-1)*(Q-1)>=1一定成立,通过展开我们可以得到N=P*Q>=P+Q;

我们得到的这个式子的含义是什么呢?  倘若N=6;P=2,Q=3; 我们只需要得到2个A然后复制、粘贴2次即可(而复制、粘贴P子串的操作数为Q)

int minSteps(int n) {
        if(n<=1)
          return 0;
       int d=2;
       int result=0;
       while(n>1)
       {
           //如果d是n的一个因数,我们需要得到一个n/d的子串进行d次操作
           while(n%d==0)
           {
               result+=d;
               n/=d;
           }
           d++;
       }
       return result;
    }

 注:如果本篇博客有任何错误和建议,欢迎伙伴们留言,你快说句话啊!

在 C 语言中,给定两个无序整数数组 A 和 B,要找到它们的交集,可以使用哈希集合(如标准库中的 `std::unordered_set` 或自定义的散列表结构)来解决这个问题。以下是基本步骤: 1. 创建一个空的哈希集合(集合不会包含重复元素)。 2. 遍历数组 A,将每个元素添加到集合中。 3. 再次遍历数组 B,对于集合中已存在的元素(即存在于数组 A 中),记录下来。 4. 返回收集到的所有共同元素。 下面是一个简单的示例代码片段: ```c #include <stdio.h> #include <stdlib.h> #define MAX_SIZE 100 typedef struct Node { int data; struct Node* next; } Node; // 自定义链表辅助函数 Node* createSet(int arr[], int n) { Node* head = NULL; for (int i = 0; i < n; i++) { if (!head) { head = (Node*)malloc(sizeof(Node)); head->data = arr[i]; head->next = NULL; } else { Node* temp = head; while (temp->next != NULL && arr[i] > temp->next->data) temp = temp->next; if (arr[i] <= temp->next->data) continue; Node* newNode = (Node*)malloc(sizeof(Node)); newNode->data = arr[i]; newNode->next = temp->next; temp->next = newNode; } } return head; } int* intersect(int* nums1, int m, int* nums2, int n) { Node* set = createSet(nums1, m); int intersection[MAX_SIZE] = {0}; int count = 0; for (int i = 0; i < n; i++) { if (find(set, nums2[i])) { intersection[count++] = nums2[i]; } } // 如果没有任何交集,返回空指针 if (count == 0) return NULL; // 缩小结果数组大小并返回 intersection[count] = 0; return intersection; } // 查找链表中是否存在指定值 int find(Node* head, int value) { while (head != NULL && head->data != value) head = head->next; return head != NULL; } void printArray(int arr[], int size) { Node* temp = arr; while (temp != NULL) { printf("%d ", temp->data); temp = temp->next; } printf("\n"); } int main() { int nums1[] = {1, 2, 2, 1}; // 示例数组 A int nums2[] = {2, 2}; // 示例数组 B int m = sizeof(nums1) / sizeof(nums1[0]); int n = sizeof(nums2) / sizeof(nums2[0]); int* result = intersect(nums1, m, nums2, n); if (result) { printf("Intersection: "); printArray(result, count); } else { printf("No common elements.\n"); } free(result); // 释放内存 return 0; } ``` 在这个例子中,我们首先创建了一个链表表示数组 A 的唯一元素,然后遍历数组 B,查找链表中存在的元素,并将它们存入新数组 `intersection`。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值