선에서 세그먼트의 시작 및 끝 위치가 주어지면 작업은 주어진 모든 세그먼트의 합집합을 취하고 이러한 세그먼트가 포함하는 길이를 찾는 것입니다.
예:
Input : segments[] = {{2 5} {4 8} {9 12}} Output : 9 Explanation: segment 1 = {2 5} segment 2 = {4 8} segment 3 = {9 12} If we take the union of all the line segments we cover distances [2 8] and [9 12]. Sum of these two distances is 9 (6 + 3) 접근하다:
이 알고리즘은 1977년 Klee에 의해 제안되었습니다. 알고리즘의 시간 복잡도는 O(N log N)입니다. 이 알고리즘은 (점근적으로) 가장 빠르며 이 문제는 더 나은 복잡성으로 해결할 수 없다는 것이 입증되었습니다.
설명 :
1) 모든 세그먼트의 모든 좌표를 보조 배열 points[]에 넣습니다.
2) 좌표값을 기준으로 정렬합니다.
3) 정렬을 위한 추가 조건 - 동일한 좌표가 있는 경우 오른쪽 세그먼트 대신 왼쪽 좌표인 좌표를 삽입합니다.
4) 이제 겹치는 세그먼트의 카운터 '수'를 사용하여 전체 배열을 살펴봅니다.
5) 개수가 0보다 크면 결과는 포인트[i] - 포인트[i-1] 간의 차이에 추가됩니다.
6) 현재 요소가 왼쪽 끝에 속하면 'count'를 늘리고 그렇지 않으면 줄입니다.
삽화:
Lets take the example : segment 1 : (25) segment 2 : (48) segment 3 : (912) Counter = result = 0; n = number of segments = 3; for i=0 points[0] = {2 false} points[1] = {5 true} for i=1 points[2] = {4 false} points[3] = {8 true} for i=2 points[4] = {9 false} points[5] = {12 true} Therefore : points = {2 5 4 8 9 12} {f t f t f t} after applying sorting : points = {2 4 5 8 9 12} {f f t t f t} Now for i=0 result = 0; Counter = 1; for i=1 result = 2; Counter = 2; for i=2 result = 3; Counter = 1; for i=3 result = 6; Counter = 0; for i=4 result = 6; Counter = 1; for i=5 result = 9; Counter = 0; Final answer = 9; C++ // C++ program to implement Klee's algorithm #include using namespace std; // Returns sum of lengths covered by union of given // segments int segmentUnionLength(const vector< pair <intint> > &seg) { int n = seg.size(); // Create a vector to store starting and ending // points vector <pair <int bool> > points(n * 2); for (int i = 0; i < n; i++) { points[i*2] = make_pair(seg[i].first false); points[i*2 + 1] = make_pair(seg[i].second true); } // Sorting all points by point value sort(points.begin() points.end()); int result = 0; // Initialize result // To keep track of counts of // current open segments // (Starting point is processed // but ending point // is not) int Counter = 0; // Traverse through all points for (unsigned i=0; i<n*2; i++) { // If there are open points then we add the // difference between previous and current point. // This is interesting as we don't check whether // current point is opening or closing if (Counter) result += (points[i].first - points[i-1].first); // If this is an ending point reduce count of // open points. (points[i].second)? Counter-- : Counter++; } return result; } // Driver program for the above code int main() { vector< pair <intint> > segments; segments.push_back(make_pair(2 5)); segments.push_back(make_pair(4 8)); segments.push_back(make_pair(9 12)); cout << segmentUnionLength(segments) << endl; return 0; }
Java // Java program to implement Klee's algorithm import java.io.*; import java.util.*; class GFG { // to use create a pair of segments static class SegmentPair { int xy; SegmentPair(int xx int yy){ this.x = xx; this.y = yy; } } //to create a pair of points static class PointPair{ int x; boolean isEnding; PointPair(int xx boolean end){ this.x = xx; this.isEnding = end; } } // creates the comparator for comparing objects of PointPair class static class Comp implements Comparator<PointPair> { // override the compare() method public int compare(PointPair p1 PointPair p2) { if (p1.x < p2.x) { return -1; } else { if(p1.x == p2.x){ return 0; }else{ return 1; } } } } public static int segmentUnionLength(List<SegmentPair> segments){ int n = segments.size(); // Create a list to store // starting and ending points List<PointPair> points = new ArrayList<>(); for(int i = 0; i < n; i++){ points.add(new PointPair(segments.get(i).xfalse)); points.add(new PointPair(segments.get(i).ytrue)); } // Sorting all points by point value Collections.sort(points new Comp()); int result = 0; // Initialize result // To keep track of counts of // current open segments // (Starting point is processed // but ending point // is not) int Counter = 0; // Traverse through all points for(int i = 0; i < 2 * n; i++) { // If there are open points then we add the // difference between previous and current point. // This is interesting as we don't check whether // current point is opening or closing if (Counter != 0) { result += (points.get(i).x - points.get(i-1).x); } // If this is an ending point reduce count of // open points. if(points.get(i).isEnding) { Counter--; } else { Counter++; } } return result; } // Driver Code public static void main (String[] args) { List<SegmentPair> segments = new ArrayList<>(); segments.add(new SegmentPair(25)); segments.add(new SegmentPair(48)); segments.add(new SegmentPair(912)); System.out.println(segmentUnionLength(segments)); } } // This code is contributed by shruti456rawal
Python3 # Python program for the above approach def segmentUnionLength(segments): # Size of given segments list n = len(segments) # Initialize empty points container points = [None] * (n * 2) # Create a vector to store starting # and ending points for i in range(n): points[i * 2] = (segments[i][0] False) points[i * 2 + 1] = (segments[i][1] True) # Sorting all points by point value points = sorted(points key=lambda x: x[0]) # Initialize result as 0 result = 0 # To keep track of counts of current open segments # (Starting point is processed but ending point # is not) Counter = 0 # Traverse through all points for i in range(0 n * 2): # If there are open points then we add the # difference between previous and current point. if (i > 0) & (points[i][0] > points[i - 1][0]) & (Counter > 0): result += (points[i][0] - points[i - 1][0]) # If this is an ending point reduce count of # open points. if points[i][1]: Counter -= 1 else: Counter += 1 return result # Driver code if __name__ == '__main__': segments = [(2 5) (4 8) (9 12)] print(segmentUnionLength(segments))
C# using System; using System.Collections; using System.Collections.Generic; using System.Linq; // C# program to implement Klee's algorithm class HelloWorld { class GFG : IComparer<KeyValuePair<int bool>> { public int Compare(KeyValuePair<int bool> xKeyValuePair<int bool> y) { // CompareTo() method return x.Key.CompareTo(y.Key); } } // Returns sum of lengths covered by union of given // segments public static int segmentUnionLength(List<KeyValuePair<intint>> seg) { int n = seg.Count; // Create a vector to store starting and ending // points List<KeyValuePair<int bool>> points = new List<KeyValuePair<int bool>>(); for(int i = 0; i < 2*n; i++){ points.Add(new KeyValuePair<int bool> (0true)); } for (int i = 0; i < n; i++) { points[i*2] = new KeyValuePair<int bool> (seg[i].Key false); points[i*2 + 1] = new KeyValuePair<int bool> (seg[i].Value true); } // Sorting all points by point value GFG gg = new GFG(); points.Sort(gg); int result = 0; // Initialize result // To keep track of counts of // current open segments // (Starting point is processed // but ending point // is not) int Counter = 0; // Traverse through all points for (int i=0; i<n*2; i++) { // If there are open points then we add the // difference between previous and current point. // This is interesting as we don't check whether // current point is opening or closing if (Counter != 0) result += (points[i].Key - points[i-1].Key); // If this is an ending point reduce count of // open points. if(points[i].Value != false){ Counter--; } else{ Counter++; } } return result; } static void Main() { List<KeyValuePair<intint>> segments = new List<KeyValuePair<intint>> (); segments.Add(new KeyValuePair<intint> (2 5)); segments.Add(new KeyValuePair<intint> (4 8)); segments.Add(new KeyValuePair<intint> (9 12)); Console.WriteLine(segmentUnionLength(segments)); } } // The code is contributed by Nidhi goel.
JavaScript // JavaScript program to implement Klee's algorithm // Returns sum of lengths covered by union of given // segments function segmentUnionLength(seg) { let n = seg.length; // Create a vector to store starting and ending // points let points = new Array(2*n); for (let i = 0; i < n; i++) { points[i*2] = [seg[i][0] false]; points[i*2 + 1] = [seg[i][1] true]; } // Sorting all points by point value points.sort(function(a b){ return a[0] - b[0]; }); let result = 0; // Initialize result // To keep track of counts of // current open segments // (Starting point is processed // but ending point // is not) let Counter = 0; // Traverse through all points for (let i=0; i<n*2; i++) { // If there are open points then we add the // difference between previous and current point. // This is interesting as we don't check whether // current point is opening or closing if (Counter) result += (points[i][0] - points[i-1][0]); // If this is an ending point reduce count of // open points. if(points[i][1]){ Counter = Counter - 1; } else{ Counter = Counter + 1; } } return result; } let segments = new Array(); segments.push([2 5]); segments.push([4 8]); segments.push([9 12]); console.log(segmentUnionLength(segments)); // The code is contributed by Gautam goel (gautamgoel962)
산출
9
시간 복잡도: O(n * 로그 n)
보조 공간: 에)
경찰 부국장