leetcode 解题报告(31-36)

31. Next Permutation

题目描述: 找到全排列中按升序的下一个排列,如123—132,213----231.如果已经是最大值排列,那么返回最小值排列。

解题思路: 思路比较简单,就是从后往前,找到第一个不符合排列规律的数,然后再在它后面找一个最小的大于他的数,交换位置,最后把后面的数排序从而取得最小值排列。可以确定的是,从后往前,也就是从右往左,如果是按升序排列的,那么就是规则的,也就是找到第一个左边数小于右边数的位置就行。错了很多次,是因为边界条件没有理清楚,后面突然顿悟。C++还有一个库函数,一条代码解决。。。。

AC代码:

# python
class Solution(object):
    def nextPermutation(self, nums):
        """
        :type nums: List[int]
        :rtype: None Do not return anything, modify nums in-place instead.
        """
        tmp = len(nums)-2
        while tmp >= 0 and nums[tmp] >= nums[tmp+1]: tmp -= 1 # 找到第一个不符合条件的位置
        if tmp >= 0:
            i = 1
            while tmp >= 0 and nums[-i] <= nums[tmp]: i += 1 # 找到这个位置后面最小的大于该位置数的数
            nums[tmp],nums[-i] = nums[-i],nums[tmp] # 交换位置
            nums[tmp+1:] = sorted(nums[tmp+1:]) # 排序
        else:
            nums.sort() # 最小值序列

32. Longest Valid Parentheses

题目描述: 给一个全由左右 括号组成的字符串,找出最长的括号配对正确的子串长度。如“)(()()))”,返回6

解题思路: 乍一看题目,标成hard难度,读了一下题就跳过了,后来想想这道题似乎也不是很难。看到括号匹配,那么不出意外就是用栈来解决,但是传统的栈并不奏效,因此要改良一下,首先栈里记录的信息,除了记录左括号以外,还可能记录右括号,另外,还要附加一条重要的信息,就是当前字符的位置,这样才能结算答案。然后碰到左括号,进栈,这没问题,碰到右括号就要分情况讨论了,
1)如果此时栈顶存的是左括号,那么可以弹出,并且结算距离。
2)如果此时栈顶存的是右括号,那么不匹配,直接把当前的右括号一并进栈。
3)如果此时栈为空,那么也属于不匹配,仍然压栈。

接下来的一步很关键,就是结算距离,也就是结算答案,每次从栈中弹出元素,就说明匹配是成功的,这时候的距离,应该是当前右括号,到栈顶的左括号的下一个元素的位置,这点很关键,因为如果直接结算这左右括号的距离就会产生一种误判,如"()()()"这样的串,答案最终会结算成2。所以应该结算的是当前位置到栈中倒数第二个位置的元素的距离。
那么这样又出现了一个新的问题,如果栈为空,就无法找到栈中的第二个元素,也就会产生前文所诉的误判,那么为了解决这个问题,可以在初始化栈的时候,就先压入一个右括号,并且把他的下标设为-1,以保证每次从栈中弹出元素时,栈里都至少存在两个元素,这样不仅解决了这个问题,也简化了代码的判断逻辑,从三种情况,简化到了两种情况。

AC代码:

class Solution(object):
    def longestValidParentheses(self,s):
        res = [(-1,')')] # 初始先放入一个右括号,保证栈不为空
        ans = 0
        for j,i in enumerate(s):
            if i == '(': # 碰到左括号,压栈
                res.append((j,'('))
            elif i == ')' and res[-1][1] == '(': # 碰到右括号,如果栈顶存在左括号,那么弹出,并结算距离
                ans = max(ans,j-res[-2][0])
                res.pop()
            else: # 如果栈顶不是左括号,那么将此时的右括号也压入栈中。
                res.append((j,')'))
        return ans

33. Search in Rotated Sorted Array

题目描述: 在发生位移的升序数组里找一个数,要求时间复杂度O(logN)以内。如在4567123找2。

解题思路: 一看题就可以知道是一个典型的二分,只不过需要多加几条判断去控制左右区间的选择。再理解一下题目可以发现,这样的序列是有一个性质的,那就是,要么左半边是升序的序列,要么右半边是升序的序列。要么都是升序的序列。总以会有一边是升序的,那就可以利用这点来解题。

AC代码:

// C++
class Solution {
public:
    int search(vector<int>& nums, int target) {
        int left = 0,right = nums.size()-1,mid;
        while(left <= right)
        {
            mid = (left+right)/2;   
            if (nums[mid] == target) return mid; // 前面这些都是标准的二分步骤
            else if (nums[left] <= nums[mid] && (target >= nums[left] && target <= nums[mid]))
                right = mid-1;  // 如果左边是升序的,并且目标值属于这个区间,那么去左区间二分。
            else if (nums[mid] <= nums[right] && (target >= nums[mid] && target <= nums[right]))
                left = mid+1;  // 如果右边是升序的,并且目标值属于这个区间,那么去右区间二分。
            else if (nums[left] <= nums[mid])
                left = mid+1;  // 如果左边是升序的,而目标值不属于这个区间,那么去右区间二分。
            else 
                right = mid-1; // 反之,去左半边二分
        }
        return -1; // 找不到目标值返回-1
    }
};

34. Find First and Last Position of Element in Sorted Array

题目描述: 在有序序列目标值可能有重复,找出这个重复区间。

解题思路: C++标准库,lower_bound(),upper_bound(),基于二分查找,既然有库就不愿自己写二分了。

AC代码:

// C++
class Solution {
public:
    vector<int> searchRange(vector<int>& nums, int target) {
        vector<int> res;
        int str = lower_bound(nums.begin(),nums.end(),target) - nums.begin();
        int end = upper_bound(nums.begin(),nums.end(),target) - nums.begin()-1;
        if(str <= end)
             {res.push_back(str);res.push_back(end);}
        else
            {res.push_back(-1);res.push_back(-1);}
        return res;
    }
};

35. Search Insert Position

题目描述: 有序数组找插入位置。

解题思路: 水题+1.

AC代码:

// C++
class Solution {
public:
    int searchInsert(vector<int>& nums, int target) {
        int l = 0 , r  = nums.size()-1,mid;
        while(l <= r)
        {
            mid = (l+r)/2;
            if (nums[mid] == target) return mid;
            else if (nums[mid] < target) l = mid+1;
            else r = mid-1;
        }
        return l;
    }
};

36. Valid Sudoku

题目描述: 判断一个数独是否有效,也就是满足三个条件。
1、每行1-9不重复
2、每列1-9不重复
3、9格小方块里的数1-9无重复
一个有效的数独

解题思路: 简单题,python处理起来比较方便,一个循环搞定。当时还在琢磨,怎么没有个填数独的题,结果下一题就是,不过目前还没解出来。

AC代码:

# python
class Solution(object):
    def isValidSudoku(self,board):
        for i in range(9):
            if 10-board[i].count('.') != len(set(board[i])): # 判断行是否有效,利用set集合元素不重复的性质
                return False
            tmp = [board[j][i] for j in range(9)]
            if 10-tmp.count('.') != len(set(tmp)): # 同上,判断列是否有效
                return False
            tmp = [board[int(i/3)*3+j][int(i%3)*3+k] for j in range(3) for k in range(3)]
            if 10-tmp.count('.') != len(set(tmp)): # 判断小方格是否有效
                return False
        return True

No. xx

题目描述: 模板

解题思路: 模板

AC代码:

###

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值