题目来源
题目概述
给你一个链表的头 head ,每个结点包含一个整数值。 在相邻结点之间,请你插入一个新的结点,结点值为这两个相邻结点值的 最大公约数 。 请你返回插入之后的链表。 两个数的 最大公约数 是可以被两个数字整除的最大正整数。
示例
示例 1:
输入:head = [18,6,10,3]
输出:[18,6,6,2,10,1,3]
解释:
- 18 和 6 的最大公约数为 6 ,插入第一和第二个结点之间。
- 6 和 10 的最大公约数为 2 ,插入第二和第三个结点之间。
- 10 和 3 的最大公约数为 1 ,插入第三和第四个结点之间。 所有相邻结点之间都插入完毕,返回链表。
示例2:
输入:head = [7]
输出:[7]
解释: 没有相邻结点,所以返回初始链表。
提示
- 链表中结点数目在 [1, 5000] 之间。
- 1 <= Node.val <= 1000
思路分析
使用双指针来选中链表中的两个相邻节点,计算出这两个节点的最大公约数插入两个节点之间,并且双指针向后移动,直到后面的指针指向空。
代码实现
java实现
public class Solution {
/**
* 使用欧几里得算法(辗转相除法)求最大公约数
* @return a和b的最大公约数
*/
public int Euclid(int a, int b){
int max = Math.max(a,b);
int min = Math.min(a,b);
int mod = min;
do{
min = mod;
mod = max % min;
max =min;
}while (mod != 0);
return min;
}
public ListNode insertGreatestCommonDivisors(ListNode head) {
ListNode first = head;
ListNode second = head.next;
while (second != null) {
// 计算最大公约数
int greatestCommonDivisor = Euclid(first.val, second.val);
// 插入新节点
first.next = new ListNode(greatestCommonDivisor, second);
first = second;
second = second.next;
}
return head;
}
}
class ListNode {
int val;
ListNode next;
ListNode() {}
ListNode(int val) { this.val = val; }
ListNode(int val, ListNode next) { this.val = val; this.next = next; }
}
c++实现
struct ListNode {
int val;
ListNode* next;
ListNode() : val(0), next(nullptr) {}
ListNode(int x) : val(x), next(nullptr) {}
ListNode(int x, ListNode* next) : val(x), next(next) {}
};
class Solution {
public:
// 辗转相除法(欧几里得算法)求最大公约数
int Euclid(int a, int b) {
int max = a > b ? a : b;
int min = a > b ? b : a;
int mod = min;
do {
min = mod;
mod = max % min;
max = min;
} while (mod != 0);
return min;
}
ListNode* insertGreatestCommonDivisors(ListNode* head) {
ListNode* first = head;
ListNode* second = head->next;
while (second != nullptr) {
int greatestCommonDivisor = Euclid(first->val, second->val);
ListNode* newNode = new ListNode(greatestCommonDivisor, second);
first->next = newNode;
first = second;
second = second->next;
}
return head;
}
};