Lesson 239 of 250
2807. Insert Greatest Common Divisors in Linked List
NeetCode: Insert Greatest Common Divisors in Linked List · LeetCode: 2807. Insert Greatest Common Divisors in Linked List · Difficulty: Medium
Given the head of a linked list of positive integers, insert between every two adjacent nodes a new node whose value is the greatest common divisor (GCD) of those two nodes. Return the head.
Example
Input: 18 -> 6 -> 10 -> 3
Output: 18 -> 6 -> 6 -> 2 -> 10 -> 1 -> 3
Input: 7
Output: 7The GCD comes from Euclid's algorithm: gcd(a, 0) = a and gcd(a, b) = gcd(b, a % b). The larger argument at least halves every two steps, so it takes O(log(min(a, b))) time.
The list uses the ListNode class from LeetCode: an int val and a next reference that is null at the end of the list. Java linked structures use null and mutable fields directly.
Brute force: copy to an ArrayList and rebuild
Read the values into an ArrayList, build a second list where a gcd is placed between each adjacent pair, and rebuild a linked list from it. This allocates a whole new list and copies every value.
import java.util.ArrayList;
import java.util.List;
class ListNode {
int val;
ListNode next;
ListNode(int val) {
this.val = val;
}
ListNode(int val, ListNode next) {
this.val = val;
this.next = next;
}
}
class Solution {
private int gcd(int a, int b) {
return b == 0 ? a : gcd(b, a % b);
}
public ListNode insertGreatestCommonDivisors(ListNode head) {
List<Integer> values = new ArrayList<>();
for (ListNode cur = head; cur != null; cur = cur.next) {
values.add(cur.val);
}
List<Integer> out = new ArrayList<>();
for (int i = 0; i < values.size(); i++) {
if (i > 0) {
out.add(gcd(values.get(i - 1), values.get(i)));
}
out.add(values.get(i));
}
ListNode dummy = new ListNode(0);
ListNode tail = dummy;
for (int v : out) {
tail.next = new ListNode(v);
tail = tail.next;
}
return dummy.next;
}
}
public class Main {
// Helpers for the example: build a list from its values and read it back.
static ListNode fromArray(int... values) {
ListNode head = null;
for (int i = values.length - 1; i >= 0; i--) {
head = new ListNode(values[i], head);
}
return head;
}
static List<Integer> toList(ListNode head) {
List<Integer> out = new ArrayList<>();
for (ListNode cur = head; cur != null; cur = cur.next) {
out.add(cur.val);
}
return out;
}
public static void main(String[] args) {
Solution s = new Solution();
System.out.println(toList(s.insertGreatestCommonDivisors(fromArray(18, 6, 10, 3))));
System.out.println(toList(s.insertGreatestCommonDivisors(fromArray(7))));
}
}[18, 6, 6, 2, 10, 1, 3]
[7]Time: O(n log V), where V is the largest value (the cost of the gcd calls). Space: O(n) for the copy and the new list.
Optimal: splice new nodes in place
Walk the list once. At a node cur with a successor nxt: create a node holding gcd(cur.val, nxt.val) that points to nxt, and hang it after cur. Then move cur to nxt, skipping over the inserted node. Only the n - 1 new nodes are allocated; the original nodes are reused.
import java.util.ArrayList;
import java.util.List;
class ListNode {
int val;
ListNode next;
ListNode(int val) {
this.val = val;
}
ListNode(int val, ListNode next) {
this.val = val;
this.next = next;
}
}
class Solution {
private int gcd(int a, int b) {
return b == 0 ? a : gcd(b, a % b);
}
public ListNode insertGreatestCommonDivisors(ListNode head) {
ListNode cur = head;
while (cur != null && cur.next != null) {
ListNode nxt = cur.next;
cur.next = new ListNode(gcd(cur.val, nxt.val), nxt);
cur = nxt; // skip the inserted node
}
return head;
}
}
public class Main {
// Helpers for the example: build a list from its values and read it back.
static ListNode fromArray(int... values) {
ListNode head = null;
for (int i = values.length - 1; i >= 0; i--) {
head = new ListNode(values[i], head);
}
return head;
}
static List<Integer> toList(ListNode head) {
List<Integer> out = new ArrayList<>();
for (ListNode cur = head; cur != null; cur = cur.next) {
out.add(cur.val);
}
return out;
}
public static void main(String[] args) {
Solution s = new Solution();
System.out.println(toList(s.insertGreatestCommonDivisors(fromArray(18, 6, 10, 3))));
System.out.println(toList(s.insertGreatestCommonDivisors(fromArray(7))));
}
}[18, 6, 6, 2, 10, 1, 3]
[7]Time: O(n log V). Space: O(1) extra beyond the n - 1 nodes the answer must contain.
