将列表中的每个元素与所有先前的连续元素进行比较
Compare each element in a list with all the previous consecutive elements
我想将列表 a 的每个元素与其前面的连续元素进行比较。 i 在前向方向的每次迭代都需要 i 在后向方向的 j 迭代次数(或者简单地从 i 的当前索引反向迭代 j)并比较先前的连续元素是否满足条件 a[i] >= a[j] .如果条件为真,则计数增加 1 (count++) 如果条件失败(即 a[i] < a[j] 在任何索引处)将计数附加到新列表 li[] 并打印 li.
我尝试了以下方法但失败了:
a = [1,2,3,2,4,6,1,2]
li=[]
count = 0
for i in range(len(a)):
for j in range(i,0,-1):
while a[i] >= a[j]:
count+=1
li.append(count)
print(li)
输出应如下所示:
1 2 3 1 5 6 1 2
有什么具体的方法可以解决这个复杂度为 O(n) 的问题。比如有没有什么算法可以解决某个方法中需要2个或多个嵌套循环的问题,优化时间复杂度。
这是需要堆栈在线性时间内解决的前瞻或后视问题类别:
def smaller_preceding(a):
stack = []
result = []
for i, x in enumerate(a):
while stack and a[stack[-1]] < x:
stack.pop()
# current index minus index of last bigger element!
result.append(i - (stack[-1] if stack else -1))
stack.append(i)
return result
>>> smaller_preceding([1,2,3,2,4,6,1,2])
[1, 2, 3, 1, 5, 6, 1, 2]
堆栈跟踪严格递减元素的索引,例如在某一时刻它将是:
[2, 3]
# stack contains indeces (0 and 1 have been popped)
对应元素:
[3, 2]
# ... of decreasing elements (... because 1 and 2 were smaller than 3)
原因是对于 a
中的每个元素 x
,你知道你可以完全忘记所有更小的先前元素,因为你永远不会“过去”x
稍后回顾(如果任何更小的元素小于未来的元素,那么 x
!)。
您可以轻松验证 for
循环有 n 次迭代。
此外,可以看到 while
循环也最多有 n 次迭代(即使它是嵌套的),因为每个索引只能从堆栈中弹出一次。
因此,整个算法在时间上是线性的 space.
您可以使用 numpy 评估整体的比较 np.array
。这为您节省了一个循环。
第一步创建包含数字大于当前值的所有索引的数组:array([1, 2, 3, 4, 5]
(对于原始列表的索引 6)。
在第二步中,将空数组添加到 li
作为当前索引 +1 idx+1
因为这是该点必须返回的距离(直到列表的开头)。
如果数组非空,将添加 idx
和最大值(index
数组中最右边的索引)之间的差值。同样,这是指针必须移动的距离。
import numpy as np
a = np.array([1, 2, 3, 2, 4, 6, 1, 2])
li = []
for idx, val in enumerate(a):
index = np.where(a[0:idx+1] > val)
if np.size(index) == 0:
li.append(idx+1)
else:
li.append(idx - np.max(index))
print(li)
我想将列表 a 的每个元素与其前面的连续元素进行比较。 i 在前向方向的每次迭代都需要 i 在后向方向的 j 迭代次数(或者简单地从 i 的当前索引反向迭代 j)并比较先前的连续元素是否满足条件 a[i] >= a[j] .如果条件为真,则计数增加 1 (count++) 如果条件失败(即 a[i] < a[j] 在任何索引处)将计数附加到新列表 li[] 并打印 li.
我尝试了以下方法但失败了:
a = [1,2,3,2,4,6,1,2]
li=[]
count = 0
for i in range(len(a)):
for j in range(i,0,-1):
while a[i] >= a[j]:
count+=1
li.append(count)
print(li)
输出应如下所示:
1 2 3 1 5 6 1 2
有什么具体的方法可以解决这个复杂度为 O(n) 的问题。比如有没有什么算法可以解决某个方法中需要2个或多个嵌套循环的问题,优化时间复杂度。
这是需要堆栈在线性时间内解决的前瞻或后视问题类别:
def smaller_preceding(a):
stack = []
result = []
for i, x in enumerate(a):
while stack and a[stack[-1]] < x:
stack.pop()
# current index minus index of last bigger element!
result.append(i - (stack[-1] if stack else -1))
stack.append(i)
return result
>>> smaller_preceding([1,2,3,2,4,6,1,2])
[1, 2, 3, 1, 5, 6, 1, 2]
堆栈跟踪严格递减元素的索引,例如在某一时刻它将是:
[2, 3]
# stack contains indeces (0 and 1 have been popped)
对应元素:
[3, 2]
# ... of decreasing elements (... because 1 and 2 were smaller than 3)
原因是对于 a
中的每个元素 x
,你知道你可以完全忘记所有更小的先前元素,因为你永远不会“过去”x
稍后回顾(如果任何更小的元素小于未来的元素,那么 x
!)。
您可以轻松验证 for
循环有 n 次迭代。
此外,可以看到 while
循环也最多有 n 次迭代(即使它是嵌套的),因为每个索引只能从堆栈中弹出一次。
因此,整个算法在时间上是线性的 space.
您可以使用 numpy 评估整体的比较 np.array
。这为您节省了一个循环。
第一步创建包含数字大于当前值的所有索引的数组:array([1, 2, 3, 4, 5]
(对于原始列表的索引 6)。
在第二步中,将空数组添加到 li
作为当前索引 +1 idx+1
因为这是该点必须返回的距离(直到列表的开头)。
如果数组非空,将添加 idx
和最大值(index
数组中最右边的索引)之间的差值。同样,这是指针必须移动的距离。
import numpy as np
a = np.array([1, 2, 3, 2, 4, 6, 1, 2])
li = []
for idx, val in enumerate(a):
index = np.where(a[0:idx+1] > val)
if np.size(index) == 0:
li.append(idx+1)
else:
li.append(idx - np.max(index))
print(li)