++递归 字符串全排列_剑指Offer整理5-递归+动态规划+贪心

这篇博客详细介绍了递归、动态规划和贪心策略在解决编程问题中的应用,包括斐波那契数列、矩形覆盖、跳台阶等经典问题。同时,重点讨论了字符串的全排列问题,并与其他类似问题如变态跳台阶、剪绳子等进行对比分析。此外,还探讨了二分查找和穷举法在旋转数组和丑数问题中的应用,以及矩阵路径的dfs回溯法解决方案。
摘要由CSDN通过智能技术生成

35f2098bc3252e224cb9835e66bc4f9e.png

专题4 递归+动态规划+贪心

知识点1 递归+动态规划

1.斐波那契数列

题目描述

大家都知道斐波那契数列,现在要求输入一个整数n,请你输出斐波那契数列的第n项(从0开始,第0项为0,第1项是1)。 n<=39

Python:
# -*- coding:utf-8 -*-
#递归时间复杂度太高,采用动态规划做
#参考:https://blog.csdn.net/u013309870/article/details/75193592

class Solution:
    def Fibonacci(self, n):
        # write code here  
        #原地交换
        #f1=0
        #f2=1
        #for i in range(n):
            #f1,f2=f2,f1+f2
        #return f1
-------------------------------------------------------------------------------------------
        if n == 0:
            return 0
        if n == 1:
            return 1
        a = 0
        b = 1
        res = 0
        for i in range(n-1):
            res = a + b
            a = b
            b = res
        return b
-------------------------------------------------------------------------------------------  
        # write code here
        res=[0,1]
        while len(res)<=n:
            res.append(res[-1]+res[-2])
        return res[n]

-------------------------------------------------------------------------------------------
-------------------------------------------------------------------------------------------
C++
class Solution {
public:
    int Fibonacci(int n) {
 
        int result[2] = {0,1};
        if (n < 2)
            {
            return result[n];
        }
        int a = 0;
        int b = 1;
        int res = 0;
        for (int i = 2; i <= n ;i++)
            {
            res = a + b;
            a = b;
            b = res;
        }
        return res;

    }
};

2.矩形覆盖

题目描述

我们可以用2*1的小矩形横着或者竖着去覆盖更大的矩形。请问用n个2*1的小矩形无重叠地覆盖一个2*n的大矩形,总共有多少种方法?

比如n=3时,2*3的矩形块有3种覆盖方法:

fefe15707bc42707fa7d4a42533316c7.png
Python
# -*- coding:utf-8 -*-
class Solution:
    def rectCover(self, number):
        # write code here
        n = number
        if n <= 0:
            return 0
        if n == 1:
            return 1
        if n == 2:
            return 2
        a = 1
        b = 2
        res = 0
        for i in range(3,n+1):
            res = a + b
            a = b
            b = res
        return b

3.跳台阶

题目描述

一只青蛙一次可以跳上1级台阶,也可以跳上2级。求该青蛙跳上一个n级的台阶总共有多少种跳法(先后次序不同算不同的结果)。

Python
# -*- coding:utf-8 -*-
class Solution:
    def jumpFloor(self, number):
        # write code here
        if number <= 0:
            return False
        if number == 1:
            return 1
        if number == 2:
            return 2
        a = 1
        b = 2
        res = 0
        for i in range(number-2):
            res = a + b
            a = b
            b = res
        return res

3-1.跳台阶改版 ---20200906字节笔试

cb21c06678754382cf9245a8079115fc.png

1988754884ee86300da2d2db02127ba0.png
##字节0906 有限制的走楼梯

'''
dp[i][0/1]表示跳到第i层,
0/1 表示上一次跳跃是不是两格,
显然有dp[i][0]=dp[i-1][1]+dp[i-1][0], dp[i][1]=dp[i-2][0]。

那么答案即dp[n][0]+dp[n][1]。

首先需要令dp[0][0]=1,然后从i=1递推上去即可
'''
n = int(input())
N = 105
if n == 0:
    print(0)

else:
    dp = [[0]* 2 for _ in range(N)]
    dp[0][0] = 1

    for i in range(1, N):
        dp[i][0] = dp[i-1][0] + dp[i-1][1]

        if i>=2 :
            dp[i][1] = dp[i-2][0]

    res = dp[n][0] + dp[n][1]
    print(res)

4.字符串的全排列

题目描述

输入一个字符串,按字典序打印出该字符串中字符的所有排列。例如输入字符串abc,则按字典序打印出由字符a,b,c所能排列出来的所有字符串abc,acb,bac,bca,cab和cba。

Python
# -*- coding:utf-8 -*-
import itertools
class Solution:
    def Permutation(self, ss):
        # write code here
        #method1

        result=[]
        if not ss:
            return []
        else:
            res = itertools.permutations(ss)
            for i in res:
                if "".join(i) not in result:
                    result.append("".join(i))
        return result
'''   
        # write code here

        if len(ss) <= 1:
            return ss
        res = set()
        # 遍历字符串,固定第一个元素,第一个元素可以取a,b,c...,然后递归求解
        for i in range(len(ss)):
            for j in self.Permutation(ss[:i] + ss[i+1:]): # 依次固定了元素,其他的全排列(递归求解)
                res.add(ss[i] + j) # 集合添加元素的方法add(),集合添加去重(若存在重复字符,排列后会存在相同,如baa,baa)
        return sorted(res)   # sorted()能对可迭代对象进行排序,结果返回一个新的list
    '''

-------------------------------------------------------------------------------------------
C++
class Solution {
public:
    vector<string> Permutation(string str) {
 
        vector<string> ret;
        if(str.empty())
            return ret;
        sort(str.begin(),str.end());
        //ret.push_back(str);
        do{
            ret.push_back(str); 
        }while(next_permutation(str.begin(),str.end()));
        //while(next_permutation(str.begin(),str.end()))
             //ret.push_back(str);
 
        return ret;
    }
};

知识点2 贪心

1.变态跳台阶

题目描述

一只青蛙一次可以跳上1级台阶,也可以跳上2级……它也可以跳上n级。求该青蛙跳上一个n级的台阶总共有多少种跳法。

Python
 '''
解析:设跳上n级总共有f(n)种跳法,n-1级总共有f(n-1),n-2级总共有f(n-2)种跳法种跳法则:

  f(n) = 1+f(n-1)+f(n-2)+...+f(2)+f(1);#1代表的意思是n级台阶跳n级的跳法只有一种
  f(1) = 1;
  所以:
  f(2)=1+f(1)=1+1=2=2^1;
  f(3)=1+f(2)+f(1)=1+2+1=4=2^2;
  f(4)=1+f(3)+f(2)+f(1)=1+4+2+1=8=2^3;
  ......
 归纳:
  f(n) = 2^(n-1);(n>=1的整数)
'''
# -*- coding:utf-8 -*-
class Solution:
    def jumpFloorII(self, number):
        # write code here
        #return pow(2,number-1)
        return 2**(number-1)

2.剪绳子

题目描述

给你一根长度为n的绳子,请把绳子剪成整数长的m段(m、n都是整数,n>1并且m>1,m<=n),每段绳子的长度记为k[1],...,k[m]。请问k[1]x...xk[m]可能的最大乘积是多少?例如,当绳子的长度是8时,我们把它剪成长度分别为2、3、3的三段,此时得到的最大乘积是18。

C++
/*************************动态规划******************************/
class Solution {
public:
    int cutRope(int number) {
 
        if(number < 2)
            return 0;
        if(number == 2)
            return 1;
        if(number == 3)
            return 2;
        //int* products = new int[number+1];
        int* products = new int[number];
        products[0] = 0;
        products[1] = 1;
        products[2] = 2;
        products[3] = 3;
        int max = 0;
        for(int i=4;i<=number;i++)
        {
            max = 0;
            for(int j=1;j<=i/2;j++)
            {
                int product = products[j]*products[i-j];
                if(max<product)
                    max = product;
                products[i] = max;
            }
        }
        max = products[number];
        delete[] products;
        return max;
 
 
    }
};
/*************************贪心算法******************************/


class Solution {
public:
    int cutRope(int number) {
    if (number < 2)
        return 0;
    if (number == 2)
        return 1;
    if (number == 3)
        return 2;
 
    int timesOf3 = number / 3;
 
    /*  当最后绳子长度为 4 时,这时候分割成 2,2 而不是 3,1 因为2*2=4 > 3=3*1  */
    if (number - timesOf3 * 3 == 1)
        timesOf3--;
 
    int timesOf2 = (number - timesOf3 * 3) / 2;
 
    return (int)(pow(3, timesOf3))*(int)(pow(2, timesOf2));
    }
};

知识点3 查找+穷举

1.旋转数组的最小数字(二分查找)

题目描述

把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。输入一个非递减排序的数组的一个旋转,输出旋转数组的最小元素。例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组的最小值为1。NOTE:给出的所有元素都大于0,若数组大小为0,请返回0。

Python
# -*- coding:utf-8 -*-
class Solution:
    def minNumberInRotateArray(self, rotateArray):
        # write code here
        #method1 
        '''
        minnum = 0
        for i in range(0,len(rotateArray)):
            minnum = minnum if minnum < rotateArray[i] and minnum!=0 else rotateArray[i]
        return minnum
         '''
        #method2
        if not rotateArray:
            return 0
        left = 0
        right = len(rotateArray)-1
        while  left <= right:
            mid = (left + right) >> 1
            if rotateArray[mid] < rotateArray[mid-1]:
                return rotateArray[mid]
            elif rotateArray[mid] < rotateArray[right]:
                right = mid -1
            else:
                left = mid + 1
        return None
----------------------------------------------------------------------------------------------------
        if not rotateArray:
                return 0
           else:
                return min(rotateArray)

2.丑数(穷举)

题目描述

把只包含质因子2、3和5的数称作丑数(Ugly Number)。例如6、8都是丑数,但14不是,因为它包含质因子7。 习惯上我们把1当做是第一个丑数。求按从小到大的顺序的第N个丑数。

Python
# -*- coding:utf-8 -*-
class Solution:
    def GetUglyNumber_Solution(self, index):
        # write code here
        # write code here
        if index < 1:
            return 0
        uglylist = [1]
 
        twopoint = 0
        threepoint = 0
        fivepoint = 0
        count = 1
 
        while count != index:
            minvalue = min(2*uglylist[twopoint],3*uglylist[threepoint],5*uglylist[fivepoint])
            uglylist.append(minvalue)
            count += 1
 
            if minvalue == 2*uglylist[twopoint]:
                twopoint += 1
            if minvalue == 3*uglylist[threepoint]:
                threepoint += 1
            if minvalue == 5*uglylist[fivepoint]:
                fivepoint += 1
        return uglylist[count-1]

-----------------------------------------------------------------------------------------
C++
class Solution {
public://别人的代码就是精简,惭愧啊,继续学习。
    int GetUglyNumber_Solution(int index) {
        if (index < 7) return index;
        vector<int> res(index);
        res[0] = 1;
        int t2 = 0, t3 = 0, t5 = 0, i;
        for (i = 1; i < index; ++i)
        {
            res[i] = min(res[t2] * 2, min(res[t3] * 3, res[t5] * 5));
            if (res[i] == res[t2] * 2) t2++;
            if (res[i] == res[t3] * 3) t3++;
            if (res[i] == res[t5] * 5) t5++;
        }
        return res[index - 1];
    }
};

知识点4 dfs(回溯法)

1.矩阵中的路径

题目描述

请设计一个函数,用来判断在一个矩阵中是否存在一条包含某字符串所有字符的路径。路径可以从矩阵中的任意一个格子开始,每一步可以在矩阵中向左,向右,向上,向下移动一个格子。如果一条路径经过了矩阵中的某一个格子,则该路径不能再进入该格子。 例如

a47388c7883bf60f2cbc6ed328aab0ee.png

矩阵中包含一条字符串"bcced"的路径,但是矩阵中不包含"abcb"路径,因为字符串的第一个字符b占据了矩阵中的第一行第二个格子之后,路径不能再次进入该格子。

C++
class Solution {
public:
    bool hasPath(char* matrix, int rows, int cols, char* str)
    {
        if(matrix==nullptr || rows<1 || cols<1 || str==nullptr)
             return false;
        bool *visited = new bool[rows*cols];
        memset(visited,0,rows*cols);
 
        int pathlength = 0;
        for(int row=0; row<rows; ++row)
        {
            for(int col=0; col<cols; ++col)
            {
                if(haspathcore(matrix,rows,cols,row,col,str,
                               pathlength,visited))
                {
                    return true;
                }
            }
        }
         delete[] visited;
         return false;
    }
    bool haspathcore(const char* matrix, int rows, int cols, int row,
                    int col, const char* str, int& pathlength, bool* visited)
    {
        if(str[pathlength] == '0')
            return true;
        bool haspath = false;
        if(row>=0 && row<rows && col>=0 && col<cols
          && matrix[row*cols+col]==str[pathlength]
          && !visited[row*cols+col])
        {
            ++pathlength;
            visited[row*cols+col] = true;
            haspath = haspathcore(matrix, rows, cols, row, col-1,
                                str, pathlength, visited)
                      || haspathcore(matrix, rows, cols, row-1, col,
                                str, pathlength, visited)
                      || haspathcore(matrix, rows, cols, row, col+1,
                                str, pathlength, visited)
                      || haspathcore(matrix, rows, cols, row+1, col,
                                str, pathlength, visited);
           if(!haspath)
           {
                --pathlength;
                visited[row*cols+col] = false;
            }
        }
        return haspath;
    }

};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值