Leetcode(1)——数组、栈、队列

格式:

题号+题名+简单思路+code



T1: 两数之和

  • 不考虑去重,只找出第一个解;使用哈希表记录出现过的数字,O(N)时间复杂度
func twoSum(nums []int, target int) []int {
    if len(nums)==0 {
        return nil
    }
    tmp:=make(map[int]int,len(nums))
    for i,v := range nums {
        if j,ok:=tmp[target-v];ok {
            return []int{j,i}
        }
        tmp[v]=i
    }
    return nil
}
  • 哈希法能找出无序数组中所有和为定值的组合;但不能去重


※T560:和为K的子数组

  • 利用哈希字典找出所有和为K的子数组
  • 类似两数之和(两数之差),先转化成前缀和;前缀和用于处理数组区间问题
  • sum[j]-k=sum[i]
func subarraySum(nums []int, k int) int {
    memo:=make([]int,len(nums)+1)
    for i:=1;i<len(memo);i++ {
        memo[i]=memo[i-1]+nums[i-1]
    }
    count:=0
    dict:=make(map[int]int,0)
    for i:=0;i<len(memo);i++ {    // 注意i从0开始
        if c,ok:=dict[memo[i]-k];ok {
            count+=c
        }
        dict[memo[i]]++
    }
    return count
}



剑指57:和为s的连续正数序列

  • 同样对于连续子数组和我们转化为前缀和数组
  • 可以使用哈希表,也可以因为前缀和是有序数组,使用滑动窗口

  • 哈希表
class Solution:
    def findContinuousSequence(self, target: int) -> List[List[int]]:
        if target<=2:
            return []
        tmp=[i for i in range((target+1)//2+1)]
        pre=0
        for i in range(len(tmp)):
            tmp[i]=pre+tmp[i]
            pre=tmp[i]
        memo=dict()
        ans=[]
        for i in range(len(tmp)):
            if tmp[i]-target in memo:
                ans.append([j for j in range(memo[tmp[i]-target]+1, i+1)])
            memo[tmp[i]]=i
        return ans
  • 滑动窗口
class Solution:
    def findContinuousSequence(self, target: int) -> List[List[int]]:
        if target<=2:
            return []
        tmp=[i for i in range((target+1)//2+1)]
        pre=0
        for i in range(len(tmp)):
            tmp[i]=pre+tmp[i]
            pre=tmp[i]
        i=0
        ans=[]
        for j in range(len(tmp)):
            if tmp[j]-tmp[i]<=target:
                pass
            else:
                while j>i and tmp[j]-tmp[i]>target:
                    i+=1
            if tmp[j]-tmp[i]==target:
                ans.append([k for k in range(i+1,j+1)])
        return ans



T15:三数之和

  • 考虑去重,所有解;使用排序+双指针;最坏情况为O(N^2)时间复杂度
import "sort"
func threeSum(nums []int) [][]int {
    target:=0
    ans:=[][]int{}
    sort.Ints(nums)
    for i:=0;i<len(nums)-2;i++ {
        if nums[i]>target {
            break
        }
        if i>0 && nums[i]==nums[i-1] {
            continue
        }
        lo:=i+1
        hi:=len(nums)-1
        a:=nums[i]
        for lo<hi && lo>=i+1 && hi<=len(nums)-1 {
            b:=nums[lo]
            c:=nums[hi]
            if a+b+c > target {
                hi--
            } else if a+b+c < target {
                lo++
            } else {
                ans=append(ans,[]int{a,b,c})
                for lo<hi && nums[hi-1]==nums[hi]{
                    hi--
                }
                for lo<hi && nums[lo+1]==nums[lo] {
                    lo++
                }
                lo++
                hi--
            }
        }
    }
    return ans
}
  • python3
class Solution:
    def threeSum(self, nums: List[int]) -> List[List[int]]:
        nums=sorted(nums)
        ans=[]
        for i in range(len(nums)-2):
            if i>0 and nums[i]==nums[i-1]:
                continue
            x=nums[i]
            left=i+1
            right=len(nums)-1
            while left<right:
                if x+nums[left]+nums[right]>0:
                    while left<right and nums[right-1]==nums[right]:
                        right-=1
                    right-=1
                elif x+nums[left]+nums[right]<0:
                    while left<right and nums[left+1]==nums[left]:
                        left+=1
                    left+=1
                else:
                    ans.append([x, nums[left], nums[right]])
                    while left<right and nums[left+1]==nums[left]:
                        left+=1
                    left+=1
                    while left<right and nums[right-1]==nums[right]:
                        right-=1
                    right-=1
        return ans



T11:盛最多的水的容器

  • 双指针+短板效应;O(N)时间复杂度
func maxArea(height []int) int {
    n:=len(height)
    lo:=0
    hi:=n-1
    maxA:=0
    maxH:=0
    for lo<hi {
        if height[lo]<height[hi] {
            tmp:=(hi-lo)*height[lo]
            if tmp> maxA {
                maxA=tmp
            }
            maxH=height[lo]
            for lo<hi && height[lo+1]<=maxH {
                lo++
            }
            lo++
        } else {
            tmp:=(hi-lo)*height[hi]
            if tmp>maxA {
                maxA=tmp
            }
            maxH=height[hi]
            for lo<hi && height[hi-1]<=maxH {
                hi--
            }
            hi--
        }
    }
    return maxA
}



T16:最接近的三数之和

  • 由于计算的是和,所以无需考虑重复性;排序+双指针;O(N^2)时间复杂度
import "math"
import "sort"
func threeSumClosest(nums []int, target int) int {
    sort.Ints(nums)
    tmp:=math.Inf(0)
    var ans int
    for i:=0;i<len(nums)-2;i++ {
        if i>0 && nums[i]==nums[i-1] {
            continue
        }
        t:=nums[i]
        lo:=i+1
        hi:=len(nums)-1
        for lo<hi {
            currVal:=t+nums[lo]+nums[hi]-target
            c:=math.Abs(float64(currVal))
            if c<tmp {
                tmp=c
                ans=currVal+target
            }
            if currVal>0 {
                hi--
            } else if currVal<0 {
                lo++
            } else {
                return target
            }
        }
    }
    return ans
}




T739:每日温度

  • 单调栈(递减栈)
class Solution:
    def dailyTemperatures(self, T: List[int]) -> List[int]:
        T.append(float("inf"))
        stack=[]
        ans=[0 for i in range(len(T))]
        for idx in range(len(T)):
            while len(stack)>0 and T[stack[-1]]<T[idx]:
                tmp=stack.pop()
                ans[tmp]=0 if idx==len(T)-1 else idx-tmp
            stack.append(idx)
        return ans[:-1]



func dailyTemperatures(T []int) []int {
    stack:=[]int{}
    ans:=make([]int, len(T))
    for i:=0;i<len(T);i++ {
        for len(stack)>0 && T[stack[len(stack)-1]]<T[i] {
            ans[stack[len(stack)-1]]=i-stack[len(stack)-1]
            stack=stack[:len(stack)-1]
        }
        stack=append(stack, i)
    }
    for i:=0;i<len(stack);i++ {
        ans[stack[i]]=0
    }
    return ans
}




※T316:去除重复字母

  • 维持一个单增栈
  • 出栈时需要保证相同字母在后续也会出现,对于stack中记录的字母就略过
func removeDuplicateLetters(s string) string {
    position:=[26]int{}
    memo:=[26]bool{}
    for i:=0;i<len(s);i++ {
        position[s[i]-'a']=i
    }
    stack:=[]byte{}
    for i:=0;i<len(s);i++ {
        if memo[s[i]-'a'] {
            continue
        }
        for len(stack)>0 && stack[len(stack)-1]>s[i] && position[stack[len(stack)-1]-'a']>i {
            x:=stack[len(stack)-1]
            stack=stack[:len(stack)-1]
            memo[x-'a']=false
        }
        stack=append(stack, s[i])
        memo[s[i]-'a']=true
    }
    return string(stack)
}




T84:柱状图中的最大矩形

  • 单调栈;适用于解决如找到第一个比其大/小这样的遍历问题;将O(N^2)→O(N)
  • 如单边的数矮个问题/升温天数T739和双边的T84
  1. 保证最后一个元素出栈
  2. 更新最值
  3. 双边扩展需要在栈中加辅助数-1 / re-index
  • 使用倒数第二个索引来明确正确左边界
class Solution {
    public int largestRectangleArea(int[] heights) {
        int ans = 0;
        Stack<Integer> stack = new Stack<>();
        for (int i=0;i<heights.length;i++) {
            while (stack.size()>0 && heights[stack.peek()] > heights[i]) {
                int x = stack.peek();
                stack.pop();
                int s = stack.size()>0?stack.peek():-1;
                ans = Math.max(ans, heights[x]*(i-s-1));
            }
            stack.push(i);
        }
        while (stack.size()>0) {
            int x = stack.peek();
            stack.pop();
            int s = stack.size()>0?stack.peek():-1;
            ans = Math.max(ans, heights[x]*(heights.length-s-1));
        }
        return ans;
    }
}
  • re-index
type Stack []int

func (s *Stack) Push(i int) {
    *s=append(*s,i)
}

func (s *Stack) Pop() int {
    i:=(*s)[len(*s)-1]
    *s=(*s)[:len(*s)-1]
    return i
}

func (s Stack) Peek() int {
    return s[len(s)-1]
}

func largestRectangleArea(heights []int) int {
    flag:=-1
    maxVal:=0
    currIdx:=0
    heights=append(heights,flag)
    stack:=Stack{}
    for idx,val:=range heights {
        if len(stack)==0 || heights[stack.Peek()]<=val {
            stack.Push(idx)
        } else {
            for len(stack)>0 && heights[stack.Peek()]>val {
                currIdx=stack.Pop()
                tmp:=(idx-currIdx)*heights[currIdx]
                if tmp>maxVal {
                    maxVal=tmp
                }
            }
            stack.Push(currIdx)
            heights[currIdx]=val
        }

    }
    return maxVal
}




T85:最大矩形

  • 将该题看作m个柱状图最大矩形问题求全局最值
  • 单调栈的第一种写法,使用栈中倒数第二个索引来计算左边界
class Solution {
    public int maximalRectangle(char[][] matrix) {
        if (matrix.length==0) return 0;
        int ans = 0;
        int[] heights = new int[matrix[0].length];
        for (int i=0;i<matrix.length;i++) {
            for (int j=0;j< heights.length;j++) {
                if (matrix[i][j]=='1') heights[j]++;
                else heights[j]=0;
            }
            Stack<Integer> stack = new Stack<>();
            for (int j=0;j<heights.length;j++) {
                while (stack.size()>0 && heights[stack.peek()]>heights[j]) {
                    int idx2 = stack.pop();
                    int idx1 = stack.size()>0?stack.peek():-1;
                    ans = Math.max(ans, (j-idx1-1)* heights[idx2]);
                }
                stack.push(j);
            }
            for (int j=0;j<stack.size();j++) {
                int idx2 = stack.get(j);
                int idx1 = j>0?stack.get(j-1):-1;
                ans = Math.max(ans, (heights.length-idx1-1)*heights[idx2]);
            }
        }
        return ans;
    }
}




※T986:区间列表交集

  • 双指针;最小区间右端点;O(M+N)时间复杂度
  • 同样的逻辑不能改成左端点
  • 类似归并排序最后的归并操作
func intervalIntersection(A [][]int, B [][]int) [][]int {
    point1:=0
    point2:=0
    ans:=[][]int{}
    for point1<len(A) && point2<len(B) {
        list1:=A[point1]
        list2:=B[point2]
        left:=max(list1[0], list2[0])
        if list1[1]<list2[1] {
            if list1[1]>=list2[0] {
                ans=append(ans, []int{left, list1[1]})
            }
            point1++
        } else {
            if list1[0]<=list2[1] {
                ans=append(ans, []int{left, list2[1]})
            }
            point2++
        }
    }
    return ans
}

func max(i int, j int) int {
    if i>j {
        return i
    } else {
        return j
    }
}




T56: 合并区间

  • 区间问题,先排序
  • 从相交区间中扩展min_startmax_end
import "sort"

func merge(intervals [][]int) [][]int {
    if len(intervals)==0 {
        return nil
    }
    ans:=[][]int{}
    sort.Slice(intervals, func(i int, j int) bool {
        return intervals[i][0]<intervals[j][0]
    })
    min_start:=intervals[0][0]
    max_end:=intervals[0][1]
    for i:=1;i<len(intervals);i++ {
        if intervals[i][0]<=max_end {
            if max_end<intervals[i][1] {
                max_end=intervals[i][1]
            }
        } else {
            ans=append(ans,[]int{min_start,max_end})
            min_start=intervals[i][0]
            max_end=intervals[i][1]
        }
    }
    ans=append(ans,[]int{min_start,max_end})
    return ans
}




※T239:滑动窗口的最大值

  • 使用单调队列的结构,保持窗口内降序,这样取最大值为O(1)
  • 存放的是索引值,首先将不在窗口内的删除,再删除窗口内小于当前值的所有值,最后插入当前值,并输出窗口中第一个值作为当前最大值
  • 平均时间复杂度为O(N)
class Solution:
    def maxSlidingWindow(self, nums: List[int], k: int) -> List[int]:
        ans=[]
        window=[]
        for i,num in enumerate(nums):
            while len(window)>0 and nums[window[-1]]<num:
                window.pop()
            window.append(i)
            if i>=k-1:
                ans.append(nums[window[0]])
                if window[0]==i-k+1:
                    window=window[1:]
        return ans



T717:1bit和2bit字符

  • 回溯法
func isOneBitCharacter(bits []int) bool {
    if len(bits)==0 {
        return false
    }
    if len(bits)<2 {
        return true
    }
    if bits[len(bits)-2]==1 {
        return !isOneBitCharacterAssist(bits, len(bits)-3)
    }
    return true
}

func isOneBitCharacterAssist(bits []int, index int) bool {
    if index==-1 {
        return true
    }
    if bits[index]==0 {
        if isOneBitCharacterAssist(bits, index-1) {
            return true
        }
        if index>0 && bits[index-1]==1 {
            if isOneBitCharacterAssist(bits, index-2) {
                return true
            }
        }
    } else if index>0 && bits[index]==1 && bits[index-1]==1 {
        if isOneBitCharacterAssist(bits, index-2) {
            return true
        }
    } else {
        return false
    }
    return false
}
  • 数学法
func isOneBitCharacter(bits []int) bool {
    step:=0
    for i:=0;i<len(bits);i+=step {
        if bits[i]==1 {
            step=2
        } else {
            step=1
        }
    }
    return step==1
}



T832:翻转图像

  • O(MN)时间复杂度
func flipAndInvertImage(A [][]int) [][]int {
    for i:=0;i<len(A);i++ {
        tmp:=A[i]
        for lo,hi:=0,len(tmp)-1;lo<=hi;lo,hi=lo+1,hi-1 {
            if lo==hi {
                tmp[lo]=1-tmp[lo]
                continue
            }
            if tmp[lo]!=tmp[hi] {
                continue
            } else {
                tmp[lo]=1-tmp[lo]
                tmp[hi]=1-tmp[hi]
            }
        }
    }
    return A
}



T232:用栈实现队列

  • 使用两个栈(两次反序)来达到正序
class MyQueue:

    def __init__(self):
        """
        Initialize your data structure here.
        """
        self.stack1=[]
        self.stack2=[]


    def push(self, x: int) -> None:
        """
        Push element x to the back of queue.
        """
        self.stack2.append(x)


    def pop(self) -> int:
        """
        Removes the element from in front of queue and returns that element.
        """
        if len(self.stack1)==0:
            while len(self.stack2)>0:
                self.stack1.append(self.stack2.pop())
        if len(self.stack1)>0:
            return self.stack1.pop()
        return -1


    def peek(self) -> int:
        """
        Get the front element.
        """
        if len(self.stack1)==0:
            while len(self.stack2)>0:
                self.stack1.append(self.stack2.pop())
        if len(self.stack1)>0:
            return self.stack1[-1]
        return -1


    def empty(self) -> bool:
        """
        Returns whether the queue is empty.
        """
        return len(self.stack1)==0 and len(self.stack2)==0



# Your MyQueue object will be instantiated and called as such:
# obj = MyQueue()
# obj.push(x)
# param_2 = obj.pop()
# param_3 = obj.peek()
# param_4 = obj.empty()



T225:用队列实现栈

  • 两个队列,使用O(N)时间复杂度互相转移实现反序
    在这里插入图片描述
type MyStack struct {
    q1 []int
    q2 []int
    item int
    length int
}


/** Initialize your data structure here. */
func Constructor() MyStack {
    return MyStack{[]int{}, []int{}, -1, 0}
}


/** Push element x onto stack. */
func (this *MyStack) Push(x int)  {
    if len(this.q1)==0 {
        this.q1=append(this.q1, x)
        for idx:=0;idx<this.length;idx++ {
            x:=this.q2[0]
            this.q1=append(this.q1, x)
            this.q2=this.q2[1:]
        }
    } else if len(this.q2)==0 {
        this.q2=append(this.q2, x)
        for idx:=0;idx<this.length;idx++ {
            x:=this.q1[0]
            this.q2=append(this.q2, x)
            this.q1=this.q1[1:]
        }
    }
    this.item=x
    this.length++
}


/** Removes the element on top of the stack and returns that element. */
func (this *MyStack) Pop() int {
    var rVal int
    if len(this.q1)==0 {
        rVal=this.q2[0]
        this.q2=this.q2[1:]
        if len(this.q2)>0 {
            this.item=this.q2[0]
        }
    } else if len(this.q2)==0 {
        rVal=this.q1[0]
        this.q1=this.q1[1:]
        if len(this.q1)>0 {
            this.item=this.q1[0]
        }
    }
    this.length--
    return rVal
}


/** Get the top element. */
func (this *MyStack) Top() int {
    return this.item
}


/** Returns whether the stack is empty. */
func (this *MyStack) Empty() bool {
    return this.length==0
}


/**
 * Your MyStack object will be instantiated and called as such:
 * obj := Constructor();
 * obj.Push(x);
 * param_2 := obj.Pop();
 * param_3 := obj.Top();
 * param_4 := obj.Empty();
 */
  • 用一个队列,通过O(N)时间复杂度,类似插入排序实现反序
type MyStack struct {
    q1 []int
}


/** Initialize your data structure here. */
func Constructor() MyStack {
    return MyStack{[]int{}}
}


/** Push element x onto stack. */
func (this *MyStack) Push(x int)  {
    this.q1=append(this.q1, x)
    idx:=len(this.q1)-1
    for idx>0 {
        this.q1[idx], this.q1[idx-1]=this.q1[idx-1], this.q1[idx]
        idx--
    }
}


/** Removes the element on top of the stack and returns that element. */
func (this *MyStack) Pop() int {
    x:=this.q1[0]
    this.q1=this.q1[1:]
    return x
}


/** Get the top element. */
func (this *MyStack) Top() int {
    return this.q1[0]
}


/** Returns whether the stack is empty. */
func (this *MyStack) Empty() bool {
    return len(this.q1)==0
}


/**
 * Your MyStack object will be instantiated and called as such:
 * obj := Constructor();
 * obj.Push(x);
 * param_2 := obj.Pop();
 * param_3 := obj.Top();
 * param_4 := obj.Empty();
 */



T20:有效的括号

  • 括号问题→栈
var memo map[byte]byte = map[byte]byte{')':'(', '}':'{', ']':'['}

func isValid(s string) bool {
    stack:=[]byte{}
    for i:=0;i<len(s);i++ {
        if b, ok:=memo[s[i]];ok {
            if len(stack)==0 || stack[len(stack)-1]!=b {
                return false
            }
            stack=stack[:len(stack)-1]
        } else {
            stack=append(stack, s[i])
        }
    }
    if len(stack)>0 {
        return false
    }
    return true
}



T42:接雨水

  • s u m = s u m + min ⁡ { m a x H [ 0 : i ] , m a x H [ i : n − 1 ] } − H [ i ] sum=sum+\min\{maxH_{[0:i]},maxH_{[i:n-1]}\}-H[i] sum=sum+min{maxH[0:i],maxH[i:n1]}H[i]

  • 记忆化递归;O(N)时间复杂度;O(N)空间复杂度

func trap(height []int) int {
    memoL:=make([]int,len(height))
    for i:=0;i<len(memoL);i++ {
        memoL[i]=-1
    }
    memoR:=make([]int,len(height))
    for i:=0;i<len(memoR);i++ {
        memoR[i]=-1
    }
    sum:=0
    for i:=0;i<len(height);i++ {
        i1:=getMaxL(height, i, memoL)
        i2:=getMaxR(height, i, memoR)
        if i1>i2 {
            sum+=i2-height[i]
        } else {
            sum+=i1-height[i]
        }
    }
    return sum
}

func getMaxL(height []int, loc int, memoL []int) int {
    if loc==0 {
        memoL[0]=height[0]
        return height[0]
    }
    if memoL[loc]!=-1 {
        return memoL[loc]
    }
    tmp:=getMaxL(height, loc-1, memoL)
    if tmp>height[loc] {
        memoL[loc]=tmp
        return tmp
    } else {
        memoL[loc]=height[loc]
        return height[loc]
    }
}
func getMaxR(height []int, loc int, memoR []int) int {
    if loc==len(height)-1 {
        memoR[loc]=height[loc]
        return height[loc]
    }
    if memoR[loc]!=-1 {
        return memoR[loc]
    }
    tmp:=getMaxR(height, loc+1, memoR)
    if tmp>height[loc] {
        memoR[loc]=tmp
        return tmp
    } else {
        memoR[loc]=height[loc]
        return height[loc]
    }
}
  • s u m = s u m + min ⁡ { m a x H [ 0 : l o ] , m a x H [ h i : n − 1 ] } − H [ i ∈ { l o , h i } ] sum=sum+\min\{maxH_{[0:lo]},maxH_{[hi:n-1]}\}-H[i\in\{lo,hi\}] sum=sum+min{maxH[0:lo],maxH[hi:n1]}H[i{lo,hi}]
  • 短板效应
  • O(N)时间复杂度;O(1)空间复杂度
func trap(height []int) int {
    if len(height)==0 {
        return 0
    }
    ans:=0
    left:=height[0]
    right:=height[len(height)-1]
    point1:=0
    point2:=len(height)-1
    for point1<point2 {
        if left<right {
            if height[point1+1]<=left {
                ans+=left-height[point1+1]
            } else {
                left=height[point1+1]
            }
            point1++
        } else {
            if height[point2-1]<=right {
                ans+=right-height[point2-1]
            } else {
                right=height[point2-1]
            }
            point2--
        }
    }
    return ans
}



※T224:基本计算器

  • 利用栈存储之前的计算结果
  • + , − , ∗ , / , ( , ) +, -, *, /, (, ) +,,,/,(,)
import "unicode"

func calculate(s string) int {
    seq:=[]rune(s)
    idx:=0
    return calculateAssist(seq, &idx)
}

func calculateAssist(seq []rune, idx *int) int {
    num:=0
    sign:='+'
    ans:=0
    stack:=[]int{}
    for *idx<len(seq) {
        c:=seq[*idx]
        if unicode.IsNumber(c) {
            num=num*10+int(c-'0')
        } else if c=='(' {
            (*idx)++
            num=calculateAssist(seq, idx)
        } else if !unicode.IsSpace(c) {    // 运算符或者')'或者'.'
            if c==')' {
                break
            }
            switch sign {
                case '+':
                    stack=append(stack, num)
                case '-':
                    stack=append(stack, -num)
                case '*':
                    stack[len(stack)-1]*=num
                case '/':
                    stack[len(stack)-1]/=num
            }
            sign=c
            num=0
        }
        (*idx)++
    }
    switch sign {    // 末尾数字
        case '+':
            stack=append(stack, num)
        case '-':
            stack=append(stack, -num)
        case '*':
            stack[len(stack)-1]*=num
        case '/':
            stack[len(stack)-1]/=num
    }
    for i:=0;i<len(stack);i++ {
        ans+=stack[i]
    }
    return ans
}



T394:字符串解码

  • 十分类似于基本计算器的思路,即对括号的处理上
import "unicode"
import "bytes"

func decodeString(s string) string {
    seq:=[]rune(s)
    idx:=0
    return decodeStringAssist(seq, &idx)
}

func decodeStringAssist(seq []rune, idx *int) string {
    var tmp bytes.Buffer
    num:=0
    for *idx < len(seq) {
        c:=seq[*idx]
        if unicode.IsNumber(c) {    // 数字
            num=num*10+int(c-'0')
        } else if unicode.IsLetter(c) {    // 字母
            tmp.WriteRune(c)
        } else if c=='[' {    // '['代替了括号和乘法
            *(idx)++
            ans:=decodeStringAssist(seq, idx)
            for i:=0;i<num;i++ {
                tmp.WriteString(ans)
            }
            num=0
        } else {    // ']'表示终止
            break
        }
        *(idx)++
    }
    return tmp.String()
}



剑指04:二维数组中的查找

  • 相当于构造一棵二叉搜索树
func findNumberIn2DArray(matrix [][]int, target int) bool {
    i:=len(matrix)-1
    j:=0
    for i>=0 && j<len(matrix[0]) {
        if matrix[i][j]<target {
            j++
        } else if matrix[i][j]>target {
            i--
        } else {
            return true
        }
    }
    return false
}



※剑指45:把数组排成最小的数

  • 排序判断:任意交换相邻两个元素的位置都会使结果增大
  • 解决 3、32、34的顺序
func minNumber(nums []int) string {
    str_nums:=make([]string, len(nums))
    for i:=0;i<len(nums);i++ {
        str_nums[i]=strconv.Itoa(nums[i])
    }
    sort.Slice(str_nums, func(i int, j int) bool {
        return str_nums[i]+str_nums[j]<=str_nums[j]+str_nums[i]
    })
    return strings.Join(str_nums, "")
}



※剑指31:判断栈的压入序列、弹出序列

class Solution:
    def validateStackSequences(self, pushed: List[int], popped: List[int]) -> bool:
        stack, i = [], 0
        for num in pushed:
            stack.append(num) # num 入栈
            while stack and stack[-1] == popped[i]: # 循环判断与出栈
                stack.pop()
                i += 1
        return not stack
func validateStackSequences(pushed []int, popped []int) bool {
    stack:=[]int{}
    index:=0
    for i:=0;i<len(pushed);i++ {
        stack=append(stack, pushed[i])
        for len(stack)>0 && stack[len(stack)-1]==popped[index] {
            stack=stack[:len(stack)-1]
            index++
        }
    }
    if len(stack)==0 {
        return true
    }
    return false
}



※剑指51:数组中的逆序对

  • 基于归并排序思想
  • 在对数组进行归并排序的过程中,将无序变为有序的过程即可统计逆序对
func reversePairs(nums []int) int {
    tmp:=make([]int, len(nums))
    return mergeSort(nums, tmp, 0, len(nums)-1)
}

func mergeSort(nums []int, tmp []int, lo int, hi int) int {
    if lo>=hi {
        return 0
    }
    mid:=(hi-lo)/2+lo
    num1:=mergeSort(nums, tmp, lo, mid)
    num2:=mergeSort(nums, tmp, mid+1, hi)
    if nums[mid]<=nums[mid+1] {    // 此时已有序
        return num1+num2
    }
    count:=0
    for i:=lo;i<=hi;i++ {
        tmp[i]=nums[i]
    }
    i:=lo
    j:=mid+1
    for k:=lo;k<=hi;k++ {
        if i==mid+1 {
            nums[k]=tmp[j]
            j++
        } else if j==hi+1 {
            nums[k]=tmp[i]
            i++
        } else {
            if tmp[i]<=tmp[j] {    // 稳定排序
                nums[k]=tmp[i]
                i++
            } else {
                nums[k]=tmp[j]
                j++
                count+=mid-i+1
            }
        }
    }
    return num1+num2+count
}



T31:下一个排列

  • 若当前排列降序,则逆序输出
  • 否则找到第一个nums[i-1]<nums[i]的位置i,将nums[i-1]与nums[i:]上第一个比nums[i-1]大的元素交换位置,然后将nums[i:]逆序后输出
  • 时间复杂度O(N),空间复杂度O(1)
class Solution {
    public void nextPermutation(int[] nums) {
        if (nums.length<2) {
            return;
        }
        for (int point=nums.length-1;point>=1;point--) {
            if (nums[point-1]<nums[point]) {
                for (int index=nums.length-1;index>=point;index--) {
                    if (nums[index]>nums[point-1]) {
                        int tmp=nums[index];
                        nums[index]=nums[point-1];
                        nums[point-1]=tmp;
                        reverse(nums, point, nums.length-1);
                        return;
                    }
                }
            }
        }
        reverse(nums, 0, nums.length-1);
    }
    public void reverse(int[] nums, int start, int end) {
        for (;start<end;start++,end--) {
            int tmp=nums[start];
            nums[start]=nums[end];
            nums[end]=tmp;
        }
    }
}



T60:第k个排列

  • 注意java中静态变量和实例变量都能用于预计算
  • 通过模除得到当前应取值
class Solution {
    private static int[] memo = produceNum();
    public String getPermutation(int n, int k) {
        k--;
        int num = n;
        char[] ans = new char[n];
        boolean[] set = new boolean[n];
        while (num>=1) {
            int index = k/memo[num-1];
            k %= memo[num-1];
            int tmp=0;
            for (int i=1;i<=n;i++) {
                if (set[i-1]) {
                    continue;
                }
                if (tmp==index) {
                    set[i-1]=true;
                    ans[n-num]=(char)(i+'0');
                    break;
                }
                tmp++;
            }
            num--;
        }
        return new String(ans);
    }
    private static int[] produceNum() {
        int[] memo = new int[10];
        memo[0]=1;
        for (int i=1;i<memo.length;i++) {
            memo[i]=i*memo[i-1];
        }
        return memo;
    }
}



T75:颜色分类

  • 0/1/2 三向切分快排
  • 如何指定基准值的具体值
  • 异或法实现swap对数组交换时当取同一个值时出错
class Solution {
    public void sortColors(int[] nums) {
        for (int i=0;i< nums.length;i++) {
            if (nums[i]==1) {
                swap(nums, 0, i);
            }
        }
        quickSortTri(nums);
    }

    public void quickSortTri(int[] nums) {
        int lo = 0;
        int idx = lo+1;
        int hi = nums.length-1;
        int tmp = nums[lo];
        while (idx <= hi) {
            int c = Integer.compare(nums[idx], tmp);
            if (c<0) {
                swap(nums, lo++, idx++);
            } else if (c>0) {
                swap(nums, hi--, idx);
            } else {
                idx++;
            }
        }
    }

    public void swap(int[] nums, int idx1, int idx2) {
        int tmp = nums[idx1];
        nums[idx1] = nums[idx2];
        nums[idx2] = tmp;
    }
}



T1207:独一无二的出现次数

class Solution {
    public boolean uniqueOccurrences(int[] arr) {
        HashMap<Integer, Integer> counter = new HashMap<>();
        for (Integer i:arr) {
            counter.put(i, counter.getOrDefault(i, 0)+1);
        }
        HashSet<Integer> set = new HashSet<>();
        for (Integer i :counter.values()) {
            if (set.contains(i)) {
                return false;
            }
            set.add(i);
        }
        return true;
    }
}



T80:删除排序数组中的重复项Ⅱ

  • 排序+双指针 去重
class Solution {
    public int removeDuplicates(int[] nums) {
        if (nums.length==0) {
            return 0;
        }
        int point1 = 0, point2 = 0;
        while (point1 < nums.length) {
            int count = 0;
            while (point1 < nums.length && nums[point1] == nums[point2]) {
                if (count==1) {    // 给出最高重复数
                    nums[++point2] = nums[point1];
                }
                count++;
                point1++;
            }
            if (point1 < nums.length) {
                nums[++point2]=nums[point1];
            }
        }
        return point2+1;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值