算法进修Day-16

算法进修Day-16

下一个排列

难度:中等
题目要求:
整数数组的一个排列就是将其所有成员以序列或线性顺序排列。
整数数组的下一个排列是指其整数的下一个字典序更大的排列。更正式地,如果数组的所有排列根据其字典顺序从小到大排列在一个容器中,那么数组的下一个排列就是在这个有序容器中排在它后面的那个排列。如果不存在下一个更大的排列,那么这个数组必须重排为字典序最小的排列(即,其元素按升序排列)。
给定一个整数数组nums,找出nums的下一个排列。
必须原地修改,只允许使用额外常数空间。

示例1

输入:nums = [1,2,3]
输出:[1,3,2]

示例2

输入:nums = [3,2,1]
输出:[1,2,3]

示例3

输入:nums = [1,1,5]
输出:[1,5,1]

题解

如果数组存在更大的排列,那么一定存在一个下标ij满足 i < j ii<j n u m s [ i ] < n u m s [ j ] nums[i]nums[i]<nums[j],为了找到下一个更大的排列,应该选取符合要求的最大下标i,在nums[i]右侧寻找大于nums[i]的最小元素并将该元素与nums[i]交换,之后将nums[i]右侧的全部元素按照升序排列,就可以得到下一个排列

如果数组nums不存在更大的排列,就将整个数组反转得到单调递增的数组。就可以得到下一个排列

做法如下:

  • 反向遍历数组nums,找到符合 n u m s [ i n d e x 1 ] < n u m s [ i n d e x 1 + 1 ] nums[index_1]nums[index1]<nums[index1+1]的最大下标 i n d e x 1 index_1 index1。如果没有找到符合条件的下标 i n d e x 1 index_1 index1,则 i n d e x 1 = 1 index_1=1 index1=1
  • 如果 i n d e x 1 ≥ 0 index_1\geq0 index10,则找到符合 n u m s [ i n d e x 1 ] < n u m s [ i n d e x 2 ] nums[index_1]nums[index1]<nums[index2] 的最大下标 i n d e x 2 index_2 index2,那么一定有 i n d e x 1 < i n d e x 2 index_1index1<index2,将 n u m s [ i n d e x 1 ] nums[index_1] nums[index1] n u m s [ i n d e x 2 ] nums[index_2] nums[index2] 交换,如果 i n d e x 1 < 0 index_1<0 index1<0 则不执行
  • 将数组nums从下标 i n d e x 1 + 1 index_1+1 index1+1 到末尾的子数组反转(如果 i n d e x 1 = − 1 index_1=-1 index1=1 就将整个数组反转),最后就可以得到下一个排列

想法代码

public static void NextPermutation(int[] nums)
    {
        int length = nums.Length;
        int index1 = length - 2;
        while (index1 >= 0 && nums[index1] >= nums[index1 + 1])
        {
            index1--;
        }
        if (index1 >= 0)
        {
            int index2 = length - 1;
            while (nums[index1] >= nums[index2])
            {
                index2--;
            }
            Swap(nums, index1, index2);
        }
        Reverse(nums, index1 + 1);
    }

    public static void Swap(int[] nums, int index1, int index2)
    {
        int temp = nums[index1];
        nums[index1] = nums[index2];
        nums[index2] = temp;
    }

    public static void Reverse(int[] nums, int start)
    {
        for (int i = start, j = nums.Length - 1; i < j; i++, j--)
        {
            Swap(nums, i, j);
        }
    }

32. 最长有效括号

难度:困难
题目要求:
给你一个只包含 '('')' 的字符串,找出最长有效(格式正确且连续)括号子串的长度。

示例1

输入:s = “(()”
输出:2

示例2

输入:s = “)()())”
输出:4

示例3

输入:“”
输出:0

题解

任意的有效括号字符串满足以下条件:

  • 有效括号字符串中的左括号个数与右括号个数相等
  • 从左到右遍历有效括号字符串的过程中,任何时候遍历到左括号的个数都不会大于右括号的个数
  • 从右到左遍历有效括号字符串的过程中,任何时候遍历到右括号的个数倒不会大于左括号的个数

所以,可以从两个方向来遍历字符串并计算出最长有效括号

从左到右遍历的时候,维护左括号和右括号的计数:

  • 如果左括号与右括号的个数相等,则使用左右括号的计数之和来更新最大值
  • 如果右括号的个数大于左括号的个数,那么不可能是有效括号字符串,需要将左右括号的计数全部清零

从右到左遍历的时候,维护左括号和右括号的计数:

  • 如果右括号和左括号的个数相等,则使用左右括号的计数之和来更新最大值
  • 如果左括号的个数大于右括号的个数,那么不可能是有效括号字符串,需要将左右括号的计数全部清零

想法代码

public int LongestValidParentheses(string s)
    {
        int maxLength1 = GetMaxLength(s, 0, 1, '(');
        int maxLength2 = GetMaxLength(s, s.Length - 1, -1, ')');
        return Math.Max(maxLength1, maxLength2);
    }

    public int GetMaxLength(String s, int start, int direction, char ch)
    {
        int maxLength = 0;
        int count1 = 0, count2 = 0;
        int n = s.Length;
        for (int i = start, j = 0; j < n; i += direction, j++)
        {
            if (s[i] == ch)
            {
                count1++;
            }
            else
            {
                count2++;
            }
            if (count1 == count2)
            {
                maxLength = Math.Max(maxLength, count1 + count2);
            }
            else if (count1 < count2)
            {
                count1 = 0;
                count2 = 0;
            }
        }
        return maxLength;
    }

你可能感兴趣的:(算法进修,算法,leetcode,c#)