|
18 | 18 | 'is_ordered',
|
19 | 19 | 'upper_bound',
|
20 | 20 | 'lower_bound',
|
21 |
| - 'longest_increasing_subsequence' |
| 21 | + 'longest_increasing_subsequence', |
| 22 | + 'next_permutation', |
| 23 | + 'prev_permutation' |
22 | 24 | ]
|
23 | 25 |
|
24 | 26 | def _merge(array, sl, el, sr, er, end, comp):
|
@@ -1038,3 +1040,163 @@ def longest_increasing_subsequence(array):
|
1038 | 1040 | ans[:0] = [array[last_index]]
|
1039 | 1041 | last_index = parent[last_index]
|
1040 | 1042 | return ans
|
| 1043 | + |
| 1044 | +def _permutation_util(array, start, end, comp, perm_comp): |
| 1045 | + size = end - start + 1 |
| 1046 | + permute = OneDimensionalArray(int, size) |
| 1047 | + for i, j in zip(range(start, end + 1), range(size)): |
| 1048 | + permute[j] = array[i] |
| 1049 | + i = size - 1 |
| 1050 | + while i > 0 and perm_comp(permute[i - 1], permute[i], comp): |
| 1051 | + i -= 1 |
| 1052 | + if i > 0: |
| 1053 | + left, right = i, size - 1 |
| 1054 | + while left <= right: |
| 1055 | + mid = left + (right - left) // 2 |
| 1056 | + if not perm_comp(permute[i - 1], permute[mid], comp): |
| 1057 | + left = mid + 1 |
| 1058 | + else: |
| 1059 | + right = mid - 1 |
| 1060 | + permute[i - 1], permute[left - 1] = \ |
| 1061 | + permute[left - 1], permute[i - 1] |
| 1062 | + left, right = i, size - 1 |
| 1063 | + while left < right: |
| 1064 | + permute[left], permute[right] = permute[right], permute[left] |
| 1065 | + left += 1 |
| 1066 | + right -= 1 |
| 1067 | + result = True if i > 0 else False |
| 1068 | + return result, permute |
| 1069 | + |
| 1070 | +def next_permutation(array, **kwargs): |
| 1071 | + """ |
| 1072 | + If the function can determine the next higher permutation, it |
| 1073 | + returns `True` and the permutation in a new array. |
| 1074 | + If that is not possible, because it is already at the largest possible |
| 1075 | + permutation, it returns the elements according to the first permutation |
| 1076 | + and returns `False` and the permutation in a new array. |
| 1077 | +
|
| 1078 | + Parameters |
| 1079 | + ========== |
| 1080 | +
|
| 1081 | + array: OneDimensionalArray |
| 1082 | + The array which is to be used for finding next permutation. |
| 1083 | + start: int |
| 1084 | + The staring index of the considered portion of the array. |
| 1085 | + Optional, by default 0 |
| 1086 | + end: int, optional |
| 1087 | + The ending index of the considered portion of the array. |
| 1088 | + Optional, by default the index of the last position filled. |
| 1089 | + comp: lambda/function |
| 1090 | + The comparator which is to be used for specifying the |
| 1091 | + desired lexicographical ordering. |
| 1092 | + Optional, by default, less than is |
| 1093 | + used for comparing two values. |
| 1094 | +
|
| 1095 | +
|
| 1096 | + Returns |
| 1097 | + ======= |
| 1098 | +
|
| 1099 | + output: bool, OneDimensionalArray |
| 1100 | + First element is `True` if the function can rearrange |
| 1101 | + the given portion of the input array as a lexicographically |
| 1102 | + greater permutation, otherwise returns `False`. |
| 1103 | + Second element is an array having the next permutation. |
| 1104 | +
|
| 1105 | +
|
| 1106 | + Examples |
| 1107 | + ======== |
| 1108 | +
|
| 1109 | + >>> from pydatastructs import next_permutation, OneDimensionalArray as ODA |
| 1110 | + >>> array = ODA(int, [1, 2, 3, 4]) |
| 1111 | + >>> is_greater, next_permute = next_permutation(array) |
| 1112 | + >>> is_greater, str(next_permute) |
| 1113 | + (True, '[1, 2, 4, 3]') |
| 1114 | + >>> array = ODA(int, [3, 2, 1]) |
| 1115 | + >>> is_greater, next_permute = next_permutation(array) |
| 1116 | + >>> is_greater, str(next_permute) |
| 1117 | + (False, '[1, 2, 3]') |
| 1118 | +
|
| 1119 | + References |
| 1120 | + ========== |
| 1121 | +
|
| 1122 | + .. [1] http://www.cplusplus.com/reference/algorithm/next_permutation/ |
| 1123 | + """ |
| 1124 | + start = kwargs.get('start', 0) |
| 1125 | + end = kwargs.get('end', len(array) - 1) |
| 1126 | + comp = kwargs.get('comp', lambda x, y: x < y) |
| 1127 | + |
| 1128 | + def _next_permutation_comp(x, y, _comp): |
| 1129 | + if _comp(x, y): |
| 1130 | + return False |
| 1131 | + else: |
| 1132 | + return True |
| 1133 | + |
| 1134 | + return _permutation_util(array, start, end, comp, |
| 1135 | + _next_permutation_comp) |
| 1136 | + |
| 1137 | +def prev_permutation(array, **kwargs): |
| 1138 | + """ |
| 1139 | + If the function can determine the next lower permutation, it |
| 1140 | + returns `True` and the permutation in a new array. |
| 1141 | + If that is not possible, because it is already at the lowest possible |
| 1142 | + permutation, it returns the elements according to the last permutation |
| 1143 | + and returns `False` and the permutation in a new array. |
| 1144 | +
|
| 1145 | + Parameters |
| 1146 | + ========== |
| 1147 | +
|
| 1148 | + array: OneDimensionalArray |
| 1149 | + The array which is to be used for finding next permutation. |
| 1150 | + start: int |
| 1151 | + The staring index of the considered portion of the array. |
| 1152 | + Optional, by default 0 |
| 1153 | + end: int, optional |
| 1154 | + The ending index of the considered portion of the array. |
| 1155 | + Optional, by default the index of the last position filled. |
| 1156 | + comp: lambda/function |
| 1157 | + The comparator which is to be used for specifying the |
| 1158 | + desired lexicographical ordering. |
| 1159 | + Optional, by default, less than is |
| 1160 | + used for comparing two values. |
| 1161 | +
|
| 1162 | +
|
| 1163 | + Returns |
| 1164 | + ======= |
| 1165 | +
|
| 1166 | + output: bool, OneDimensionalArray |
| 1167 | + First element is `True` if the function can rearrange |
| 1168 | + the given portion of the input array as a lexicographically |
| 1169 | + smaller permutation, otherwise returns `False`. |
| 1170 | + Second element is an array having the previous permutation. |
| 1171 | +
|
| 1172 | +
|
| 1173 | + Examples |
| 1174 | + ======== |
| 1175 | +
|
| 1176 | + >>> from pydatastructs import prev_permutation, OneDimensionalArray as ODA |
| 1177 | + >>> array = ODA(int, [1, 2, 4, 3]) |
| 1178 | + >>> is_lower, prev_permute = prev_permutation(array) |
| 1179 | + >>> is_lower, str(prev_permute) |
| 1180 | + (True, '[1, 2, 3, 4]') |
| 1181 | + >>> array = ODA(int, [1, 2, 3, 4]) |
| 1182 | + >>> is_lower, prev_permute = prev_permutation(array) |
| 1183 | + >>> is_lower, str(prev_permute) |
| 1184 | + (False, '[4, 3, 2, 1]') |
| 1185 | +
|
| 1186 | + References |
| 1187 | + ========== |
| 1188 | +
|
| 1189 | + .. [1] http://www.cplusplus.com/reference/algorithm/prev_permutation/ |
| 1190 | + """ |
| 1191 | + start = kwargs.get('start', 0) |
| 1192 | + end = kwargs.get('end', len(array) - 1) |
| 1193 | + comp = kwargs.get('comp', lambda x, y: x < y) |
| 1194 | + |
| 1195 | + def _prev_permutation_comp(x, y, _comp): |
| 1196 | + if _comp(x, y): |
| 1197 | + return True |
| 1198 | + else: |
| 1199 | + return False |
| 1200 | + |
| 1201 | + return _permutation_util(array, start, end, comp, |
| 1202 | + _prev_permutation_comp) |
0 commit comments