private List<TopicPartition> getUnassignedPartitions(List<TopicPartition> sortedAssignedPartitions) {
            List<String> sortedAllTopics = new ArrayList<>(partitionsPerTopic.keySet());
            // sort all topics first, then we can have sorted all topic partitions by adding partitions starting from 0
            Collections.sort(sortedAllTopics);

            if (sortedAssignedPartitions.isEmpty()) {
                // no assigned partitions means all partitions are unassigned partitions
                return getAllTopicPartitions(sortedAllTopics);
            }

            List<TopicPartition> unassignedPartitions = new ArrayList<>(totalPartitionsCount - sortedAssignedPartitions.size());

            Collections.sort(sortedAssignedPartitions, Comparator.comparing(TopicPartition::topic).thenComparing(TopicPartition::partition));

            boolean shouldAddDirectly = false;
            Iterator<TopicPartition> sortedAssignedPartitionsIter = sortedAssignedPartitions.iterator();
            TopicPartition nextAssignedPartition = sortedAssignedPartitionsIter.next();

            for (String topic : sortedAllTopics) {
                int partitionCount = partitionsPerTopic.get(topic).size();
                for (int i = 0; i < partitionCount; i++) {
                    if (shouldAddDirectly || !(nextAssignedPartition.topic().equals(topic) && nextAssignedPartition.partition() == i)) {
                        unassignedPartitions.add(new TopicPartition(topic, i));
                    } else {
                        // this partition is in assignedPartitions, don't add to unassignedPartitions, just get next assigned partition
                        if (sortedAssignedPartitionsIter.hasNext()) {
                            nextAssignedPartition = sortedAssignedPartitionsIter.next();
                        } else {
                            // add the remaining directly since there is no more sortedAssignedPartitions
                            shouldAddDirectly = true;
                        }
                    }
                }
            }

            return unassignedPartitions;
        }
get the unassigned partition list by computing the difference set of all sorted partitions
and sortedAssignedPartitions. If no assigned partitions, we'll just return all sorted topic partitions.

To compute the difference set, we use two pointers technique here:

We loop through the all sorted topics, and then iterate all partitions the topic has,
compared with the ith element in sortedAssignedPartitions(i starts from 0):
  - if not equal to the ith element, add to unassignedPartitions
  - if equal to the ith element, get next element from sortedAssignedPartitions

@param sortedAssignedPartitions  sorted partitions, all are included in the sortedPartitions
@return                          the partitions not yet assigned to any consumers
clients/src/main/java/org/apache/kafka/clients/consumer/internals/AbstractStickyAssignor.java