Leetcode之Generate Parentheses、Merge k Sorted Lists、Next Permutation、Search in Rotated Sorted Array

Generate Parentheses(查找)

关键:每个位置的左括号数目大于等于右括号数目;右括号数达到时,adddList;左括号数目未到n,增加左括号数目;其他情况(x>y,x=n,y<n)时,增加右括号

class Solution {
public:
    /*关键:每个位置的左括号数目大于等于右括号数目
     *设x表示当前位置的左括号数目,y表示当前位置的右括号数目
     *if(y==n) addList
     *if(x<n) 增加左括号x=x+1;s=s+'('
     *if(x>y) 增加左括号x=x+1;s=s+'('或者增加右括号y=y+1;s=s+')'  (x=n,y<n的情况)
     */
    void generate(vector<string> &result,int x,int y,string s,int n){
        if(y==n)
            result.push_back(s);
        if(x<n)
            generate(result,x+1,y,s+'(',n);
        if(x>y)
            generate(result,x,y+1,s+')',n);
    }
    vector<string> generateParenthesis(int n) {
        vector<string> result;
        string s="";
        generate(result,0,0,s,n);
        return result;
    }
};

Merge k Sorted Lists(类比剑指offer两个有序链表排序问题)

题目描述:Merge k sorted linked lists and return it as one sorted list. Analyze and describe its complexity.
可采用以下三种方法:(代码是采用的有限队列)

  • 优先队列:使用优先队列,每次从队列中找到最小的数取出来,然后把该节点的下一个结点添加到优先队列中(如果没有后继结点则不添加),直到队列为空,这个时候所有的链表都合并结束了。【注:优先队列的push是入队+排序;默认是大堆;此题中重新定义为小堆】
  • 堆:使用堆(默认最大堆,改成最小堆,链表依次加入最小堆弹出节点,加入该节点所在链表新节点,不断调整堆.
  • 分治算法:基于两个排序链表的合并,两两合并后继续合并,每一轮复杂度o(n),n为总节点个数,T(n) = 2T(n/2) + o(n),迭代次数为lg(k),因此复杂度为o(nlgk)
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
// 思路1: 使用优先队列(实质与堆相差无几)  priority_queue,其本质就是堆
    
  //定义比较的方法,node->val小的在前面
  struct compare
   {
     bool operator()(const ListNode* l, const ListNode* r)
       {
           return l->val > r->val;
       }
   };
   ListNode *mergeKLists(vector<ListNode *> &lists)
   {
      /*priority_queue<Type, Container, Functional>Type 就是数据类型,
       *Container 就是容器类型(Container必须是用数组实现的容器,比如vector,deque等等,
       *但不能用 list。STL里面默认用的是vector),Functional 就是比较的方式,默认是大顶堆
       */
       if(lists.empty())
           return NULL;
      priority_queue<ListNode *, vector<ListNode *>,compare> q;  //compare
      for(int i=0; i<lists.size(); i++)
           if(lists[i]!=NULL)
               q.push(lists[i]);  //几个队列的队收按从小到大的入队
       ListNode *head;
       ListNode* result=new ListNode(0);
       head=result;
       /*从队列中找到最小的数取出来,然后把该数的下一个结点添加到优先队列中(如果没有后继结点则
        *不添加),直到队列为空
        */
       while(!q.empty())
       {
           result->next = q.top();
           q.pop();
           result = result->next;
           if(result->next)
               q.push(result->next);  //push:插入元素到队尾 (并排序)
       }
       return head->next;
   }
};

Next Permutation

题目描述:Implement next permutation, which rearranges numbers into the lexicographically next greater permutation of numbers. If such arrangement is not possible, it must rearrange it as the lowest possible order (ie, sorted in ascending order).The replacement must be in-place, do not allocate extra memory. Here are some examples. Inputs are in the left-hand column and its corresponding outputs are in the right-hand column.
1,2,3→1,3,2
3,2,1→1,2,3
1,1,5→1,5,1
思路:
1.从后往前找,判断是否所有的均有num[i-1]>=num[i]
2.若均存在num[i-1]>num[i],则当前的num排序为降序排序即排列组合的值最大,翻转得到最小值
3.若存在i,是的num[i-1]<num[i],表明i之后的均为降序:分为两步
step1:将i及i之后按照升序重新排序
step2:在i及i之后找到比i-1位置大的最小值,交换即可**【停止循环!】**

class Solution {
public:
    void nextPermutation(vector<int> &num) {
        bool des=true;
        int k=0;
        for(int i=num.size()-1;i>0;i--)
            if(num[i-1]<num[i]){
                des=false;
                k=i;
                break;
            }
        if(des){//num为降序排列
            sort(num.begin(),num.end()); //sort默认从小到大排序
        }else{
            sort(num.begin()+k,num.end());//将i及i之后按照从小到大排序
            //在i及i之后找到比i-1位置大的最小值,交换即可
            for(int i=k;i<num.size();i++)
                if(num[k-1]<num[i]){
                    swap(num[k-1],num[i]);
                    break;  //错误:不加break!!!
                }
        }
    }
};

Search in Rotated Sorted Array 【二分查找】

题目描述:Suppose a sorted array is rotated at some pivot unknown to you beforehand.
(i.e.,0 1 2 4 5 6 7might become4 5 6 7 0 1 2).You are given a target value to search. If found in the array return its index, otherwise return -1.You may assume no duplicate exists in the array.
分析:有一个有序数组[0,2,3,5,7,8],这个数组可能被旋转了(或未旋转)得到数组A;目标是在A中查找target,根据A是否是旋转得到的,可以分为以下两种情况:
情况1:[0,2,3,5,7,8]旋转得到A,那么A可能的情况有(pivot在8之后,0之前)[2,3,5,7,8,0] 、[3,5,7,8,0,2] 、[5,7,8,0,2,3] 、[7,8,0,2,3,5] 、[8,0,2,3,5,7];假设pivot左边的序列命名为series1,右边的序列命名为series2,可以看到两个序列均为递增的有序序列,并且series1的最小值大于series2的最大值。
情况2:[0,2,3,5,7,8]未旋转得到A,那么A=[0,2,3,5,7,8]

思路:
#如果A的第一个元素小于最后一个元素,A未被旋转,直接在A里二分查找target即可;
#如果A的第一个元素大于最后一个元素,A被旋转;那么首先找到pivot,其次在pivot两边的两个有序的子序列里二分查找target即可。

问题:怎么在A中找到pivot?仍然利用二分查找的思想

while(begin!=end){
	if(end-begin==1)
		break;
	}else{
	    //begin是series1里最小的,若都大于mid;说明begin到mid之间不是有序的,pivot在begin和mid之间
		if(A[begin]>A[mid])
			end=mid;
		else  //说明begin到mid之间是有序的,pivot在mid和end之间
			begin=mid;
	}		
}
//while循环完,begin是A中最大的,end是A中最小的
if(target>A[0])
	在(0,begin)即series1里面二分查找target
else
   在(end,A.size()-1)即series2里面二分查找target

完整代码如下:

class Solution {
public:
     /*分析:有一个有序数组[0,2,3,5,7,8],这个数组可能被旋转了(或未旋转)得到数组A;
     *目标是在A中查找target,根据A是否是旋转得到的,可以分为以下两种情况:
     *情况1:[0,2,3,5,7,8]旋转得到A,那么A可能的情况有(pivot在8之后,0之前)
     *[2,3,5,7,8,0] 、[3,5,7,8,0,2] 、[5,7,8,0,2,3] 、[7,8,0,2,3,5] 、[8,0,2,3,5,7];
     *假设pivot左边的序列命名为series1,右边的序列命名为series2,可以看到两个序列均为递增的有序
     *序列,并且series1的最小值大于series2的最大值。
     *情况2:[0,2,3,5,7,8]未旋转得到A,那么A=[0,2,3,5,7,8]
     *思路:
          #如果A的第一个元素小于最后一个元素,A未被旋转,直接在A里二分查找target即可;
          #如果A的第一个元素大于最后一个元素,A被旋转;那么首先找到pivot,其次在pivot两边的两个有序的子序列里二分查找target即可。
          
     *注:在A中找到pivot仍然利用二分查找的思想
     */
    int search(vector<int>& nums, int target) {
        int len=nums.size();
        int begin=0,end=len-1;
        if(len==0)
            return -1;
        if(nums[begin]<nums[end])
            return biSearch(nums,begin,end,target); //A未被旋转
        else{//A被旋转了
            /*step1:find the pivot*/
            //while(begin!=end){
            while(nums[begin]>nums[end]){
                int mid=(begin+end)/2;
                if(end-begin==1){
                    break;
                }else{
                    if(nums[begin]>nums[mid])
                        end=mid;
                    else
                        begin=mid;
                }
            }
            //注:while循环结束之后,begin是子序列1的最大值,end是子序列2的最小值
            /*step2:在两个子序列中分别查找*/
            //**A[0]<=target而不是小于
            if(nums[0]<=target)
                return biSearch(nums,0,begin,target);
            else
                return biSearch(nums,end,len-1,target);
        }
    }
   
    /*在数组A的begin到end之间二分查找target,找到了则返回Index,找不到返回-1
     *注:数组A的begin到end之间是有序的!!
     */
    int biSearch(vector<int>& nums,int begin,int end,int target){
        int index=-1;
        while(begin<=end){
            int mid=(begin+end)/2;
            //*注意加减1,否则运行超时
            if(nums[mid]<target)
                begin=mid+1;
            else if(nums[mid]>target)
                end=mid-1;
            else
                return mid;
        }
        return -1;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值