algorithm: 基于C++和Python(二)


感觉C++语言的算法比Python更有趣,以后还是将C++放在前面。

11.盛最多水的容器

给定一组数据,每两对数据做木桶理论求能盛的最大的水,例如我们假设一组数据第一个数和第三个数,其面积为两者索引的差*两者中较小的数。
算法思想:通过两端向中间叠进(不知道名字,双指针法?),可以有效降低时间复杂度;设置left和right变更的条件,同样可以减少判断次数,如当我们需要变更left时,变更后再比较left和left+1,如果索引left+1的值>索引left的值,则可以继续将left+1。

C++版本

class Solution{
public:
    int maxArea(vector<int> &height){
        int maxArea = 0;
        int left = 0;
        int right = height.size()-1;
        int area;
        while(left<right){
            area = (right-left)*(height[left]<height[right]? height[left]:height[right]);
            maxArea = area>maxArea? area:maxArea;
            cout<<height[left]<<"--"<<height[right]<<endl;
            if(height[left]<height[right]){
                do{
                    left++;
                }while (left<right && height[left+1]>height[left]);
            }
            else{
                do{
                    right--;
                    //cout<<(height[right])<<endl;
                }while (right>left && (height[right-1]>height[right]));
            }
        }
        return maxArea;
    }
};
int main(){
    vector<int> height {3,4,5,7,1,4,1};
    int area;
    Solution s;
    area = s.maxArea(height);
    cout<<area<<endl;
    return 0;
}

Python版本

Python版本的代码没有做太多优化

def maxarea(height):
    # height: list[int]
    ans = left = 0
    right = len(height)-1
    while left<right:
        ans = max(ans,(right-left)*min(height[left],height[right]))
        if height[left] <= height[right]:
            left += 1
        else:
            right -= 1
    return ans
print(maxarea([1,2,3,4]),maxarea([3,4,5,7,1,4,1]))

12.整数转罗马数字

将整数转化为罗马数字。
算法思想:这里不赘述了,直接代码可以看懂。

C++版本

string inttoRoman(int num){
    string symbol[] = {"M","CM","D","CD","C","XC","L","XL","X","IX","V","IV","I"};
    int value[] = {1000,900,500,400,100,90,50,40,10,9,5,4,1};
    string result;
    for(int i=0;num!=0;i++){
        while (num>=value[i]) {
            num -= value[i];
            result += symbol[i];
        }
    }
    return result;
}
int main(int argc,char** argv){
    int num=1234;
    string result;
    result = inttoRoman(num);
    cout<<num<<"\n"<<result<<endl;
    return 0;
}

Python

class Solution(object):
    def inttoRoman(self,num):
        ans = ""
        values = {"M":1000,"D":500,"C":100,"L":50,"X":10,"V":5,"I":1}
        literals = ["M","D","C","L","X","V","I"]
        for idx in [0,2,4]:
            k = num // values[literals[idx]]
            re = (num % values[literals[idx]]) // values[literals[idx+2]]
            ans += k*literals[idx]
            if re >= 9:
                ans += literals[idx+2] + literals[idx]
            elif re >= 5:
                ans += literals[idx+1] + literals[idx+2] * (re-5)
            elif re == 4:
                ans += literals[idx+2] + literals[idx+1]
            else:
                ans += re * literals[idx+2]
            num %= values[literals[idx+2]]
        return ans

te1 = Solution()
print(te1.inttoRoman(1234),te1.inttoRoman(999),te1.inttoRoman(495))

13.罗马数字转整数

12题的反向,将罗马数字转化为整数
算法思想:处理好当前数字小于后面数字的情况

C++版本

int romanchar2int(char ch){
    int d=0;
    switch (ch) {
        case 'M':
            d = 1000;
            break;
        case 'D':
            d = 500;
            break;
        case 'C':
            d = 100;
            break;
        case 'L':
            d = 50;
            break;
        case 'X':
            d = 10;
            break;
        case 'V':
            d = 5;
            break;
        case '1':
            d = 1;
            break;
    }
    return d;
};
int roman2int(string s){
    if(s.size()<=0) return 0;
    int result = romanchar2int(s[0]);
    for (int i=1; i<s.size(); i++) {
        int pre = romanchar2int(s[i-1]);
        int cur = romanchar2int(s[i]);
        if (pre < cur){
            result -= pre + pre;
        }
        result += cur;
        
    }
    return result;
}
int main(int argc,char**argv){
    string s("XL");
    int num = roman2int(s);
    cout<<s<<":"<<num<<endl;
}
int roman2Int(string rom){
    map<string,int> r2i= {{"M",1000},{"CM",900},{"D",500},{"CD",400},{"C",100},{"XC",90},{"L",50},{"XL",40},{"X",10},{"IX",9},{"V",5},{"IV",4},{"I",1}};
    int num = 0;
    string str,str2;
    for(int i=0;i<rom.size();i++){
        str = rom[i];
        str2 = rom[i];
        //cout<<"str:"<<str<<endl;
        if (r2i.find(str) != r2i.end()){
            if (i<rom.size()-1){
                str2 += rom[i+1];
                //cout<<"str2:"<<str2<<endl;
                if(r2i.find(str2) != r2i.end()) {
                    num += r2i[str2];
                    i++;
                }
                else num += r2i[str];
            }
            else num += r2i[str];
        }
        else return 0;
    }
    return num;
}

int main(int argc,char**argv){
    string s("MCDLI");
    int num = roman2Int(s);
    cout<<s<<":"<<num<<endl;
}

Python版本

def roman2int(s):
    d = {"I":1,"V":5,"X":10,"L":50,"C":100,"D":500,"M":1000}
    ans = d[s[0]]
    for i in range(1,len(s)):
        if (d[s[i-1]]<d[s[i]]):
            ans += d[s[i]] - 2 * d[s[i-1]]
        else:
            ans += d[s[i]]
    return ans

print(roman2int("MCCXL"))

14.查找字符串数组的最长公共前缀

题目可以说明问题这里不啰嗦
算法思想:这里我有两种思路,一是采用两个for循环,循环第一个字符串+循环字符数组;第二种思路是对第一个字符串采用二分法+for循环。

C++版本

string longestPrefix(vector<string> &strs){
    string pre;
    if (strs.size()<=0 || strs[0].size()<=0) return "";
    int right = strs[0].size();
    int preright = strs[0].size();
    int preleft = 0;
    while(preleft<right){
        for (int i=0;i<strs.size();i++){
            if(strs[i].size()<right) {
                preright = right;
                right = (right+preleft)/2;
                break;
            }
            if (strs[0].substr(0,right)!=strs[i].substr(0,right)){
                preright = right;
                right = (right+preleft)/2;
                break;
            }
            else {
                if (i == strs.size()-1){
                    preleft = right;
                    right = (right+preright)/2;
                }
            }
        }
    }
    pre = strs[0].substr(0,right);
    return pre;
}
int main(){
    const char* s[] = {"abab","aba","abacd"};
    vector<string> v(s,s+3);
    cout<<longestPrefix(v)<<endl;
}

Python版本

def longPrefix(strs):
    pre = strs[0][0]
    l = len(strs)
    for i in range(len(strs[0])):
        for n,j in enumerate(strs):
            if(i == 0):
                if strs[0][i] != j[i]:
                    return ""
                continue
            if(i+1 > len(j)):
                return pre

            if (strs[0][i] != j[i]):
                return pre
            else:
                if n == l-1:
                    # print(strs[0][i])
                    pre += strs[0][i]
    return pre
strs = ["ad","abc","ae"]
print(longPrefix(strs))

15.三数之和

给定一个数组nums=[-1,0,1,2,-1,-4],满足要求的三元组集合[[-1,0,1],[-1,-1,2]]。
算法思想:对数组做排序后,固定一个元素后对另外两个元素采用二分法,其中关于两个元素迭代的方法有很多优化的空间,这里并没有做优化。

C++版本

vector<vector<int>> threeSum(vector<int> &nums){
    vector<vector<int>> result;
    int n = nums.size();
    if(n<3) return result;
    sort(nums.begin(),nums.end());
   
    for(int i=0;i<n-2;i++){
        if(nums[i-1]&&nums[i-1]==nums[i]) continue;
        int left=i+1;
        int right=n-1;
        while (left<right){
            if(nums[i]+nums[left]+nums[right]>0){
                right--;
            }
            else if (nums[i]+nums[left]+nums[right]<0){
                left++;
            }
            else{
                result.push_back(vector<int>{nums[i],nums[left],nums[right]});
                right--;
                left++;
            }
        }
    }
    return result;
}
void out(vector<vector<int>> &result){
    cout<<"{";
    for(int i=0;i<result.size();i++){
        cout<<"{";
        for(int j=0;j<result[i].size();j++){
            if(j==result[i].size()-1){
                cout<<result[i][j];
                
            }
            else cout<<result[i][j]<<",";
        }
        if(i==result.size()-1){
             cout<<"}";
        }
        else cout<<"},";
    }
    cout<<"}"<<endl;
}
int main(){
    vector<int> nums = {-1,0,1,2,-1,-4};
    vector<vector<int>> result;
    result = threeSum(nums);
    out(result);
    
}

Python版本

class Solution(object):
    def threeSum(self,nums):
        nums.sort()
        n = len(nums)
        result = []
        if len(nums)<3:
            return result
        for i in range(n-2):
            if (nums[i-1] and nums[i]==nums[i-1]): continue
            left = i+1
            right = n-1
            while(left<right):
                sum = nums[i]+nums[left]+nums[right]
                if(sum>0):
                    right -= 1
                elif(sum<0):
                    left +=1
                else:
                    result.append([nums[i],nums[left],nums[right]])
                    left += 1
                    right -= 1
        return result
cla = Solution()
result = cla.threeSum([-1,0,1,2,-1,-4])
print(result)

16.最接近的三数之和

给定一个数组和目标元素,找出数组中三个元素相加最接近目标元素的情况,返回三个元素的sum。
算法思想:参考15题

C++版本

int threeSum(vector<int> &nums,int target){
    sort(nums.begin(), nums.end());
    int dis = INT_MAX;
    int result = 0;
    for(int i=0;i<nums.size()-2;i++){
        long left = i+1;
        long right = nums.size()-1;
        while (left<right) {
            int sum = nums[i] + nums[left] + nums[right];
            if(sum == target){
                dis = 0;
                return target;
            }
            else{
                if(abs(sum-target)<dis){
                    dis = abs(sum-target);
                    result = sum;
                }
                if(sum>target){
                    right--;
                }
                else{
                    left++;
                }
            }
        }
    }
    return result;
}
int main(){
    vector<int> nums = {-1,2,1,4};
    int target = 1;
    int result;
    result = threeSum(nums, target);
    cout<<result<<endl;
}

Python

class Solution(object):
    def threeSum(self,nums,target):
        nums.sort()
        dis = float("inf")
        result = 0
        n = len(nums)
        if(n<3): return result
        for i in range(n):
            if(nums[i-1] and nums[i-1]==nums[i]):
                continue
            left = i+1
            right = n-1
            while(left<right):
                sum = nums[i] + nums[left] + nums[right]
                if(sum==target): return target
                if(abs(sum-target)<dis):
                    result = sum
                if(sum>target): right -= 1
                else: left += 1
        return result
cla = Solution()
print(cla.threeSum([-1,2,1,-4],1))

17.电话号码的字母组合

给定一个仅包含2-9的字符串,返回所有它能表示的字母组合。
算法思想:可以通过递归调用,Python版本采用这种方法;C++则是通过构建两个字符向量,每增加一个数字都重新刷新整个数组。

C++版本

vector<string> int2String(string ints){
    vector<vector<string>> dictory = {{"a","b","c"},{"d","e","f"},
                                {"g","h","i"},{"j","k","l"},
                                {"m","n","o"},{"p","q","r","s"},
                                {"t","u","v"},{"w","x","y","z"}};
    vector<string> result;
    vector<string> tmp;
    if(ints.size()<=0) {return tmp;}
    for(int i=0;i<ints.size();i++){
        int n = ints[i]-'0';
        if(i==0) {
            for (int j=0; j<dictory[n-2].size(); j++) {
                tmp.push_back(dictory[n-2][j]);
                result = tmp;
            }
        }
        else{
            result = {};
            for(int j=0;j<tmp.size();j++){
                for (int k=0; k<dictory[n-2].size(); k++) {
                    result.push_back(tmp[j] + dictory[n-2][k]);
                };
            }
            tmp = result;
        }
        
    }
    return result;
}
void printVector(vector<string> & ss){
    cout<<"[";
    for(int i=0;i<ss.size();i++){
        cout<<ss[i]<<",";
        if(i==ss.size()-1) cout<<"]"<<endl;
    }
}
int main(){
    string ints = "93";
    vector<string> result;
    result = int2String(ints);
    printVector(result);
}

Python版本

def numCombination(ss):
    d = {1:"",2:"abc",3:"def",4:"ghi",5:"jkl",6:"mno",7:"pqrs",8:"tuv",9:"wxyz"}
    result = []
    if(len(ss) <= 0): return result

    def dfs(digits,index,path,res,d):
        if index == len(digits):
            res.append("".join(path))
            # print(res)
            return
        digit = int(digits[index])
        for c in d.get(digit,[]):
            path.append(c)
            dfs(digits,index+1,path,res,d)
            path.pop()
    dfs(ss,0,[],result,d)
    return result

print(numCombination("23"))

18.四数之和

给定一个包含n个整数的数组nums和一个目标值target,判断nums中是否存在四个元素a,b,c和d,使得a+b+c+d的值与d相同,找出所有满足条件且不重复的四元组。
算法思想:与上面?寻找三个整数类似,固定一个元素,双指针寻找其他元素,不过四个整数需要调用三个整数。

C++版本

vector<vector<int>> threeSum(vector<int> &nums,int target){
    vector<vector<int>> res;
    if(nums.size()<3) return res;
    sort(nums.begin(), nums.end());
    for(int i=0;i<nums.size()-2;i++){
        if(nums[i-1]&&nums[i]==nums[i-1]) continue;
        int left = i+1;
        int right = nums.size() - 1;
        while (left<right) {
            int sum;
            sum = nums[i] + nums[left] + nums[right];
            if(sum==target){
                vector<int> temp = {nums[i],nums[left],nums[right]};
                res.push_back(temp);
                left++;
                right--;
            }
            else if(sum>target){
                right--;
            }
            else{
                left++;
            }
        }
    }
    return res;
}
vector<vector<int>> fourSum(vector<int> nums,int target){
    vector<vector<int>> res;
    int n = nums.size();
    if(n<4) return res;
    sort(nums.begin(), nums.end());
    for(int i=0;i<n-3;i++){
        if(nums[i-1]&&nums[i-1]==nums[i]) continue;
        int target3 = target-nums[i];
        vector<int> num(nums.begin()+i+1,nums.end());
        vector<vector<int>> temp = threeSum(num, target3);
        for(int j=0;j<temp.size();j++){
            temp[j].insert(temp[j].begin(),nums[i]);
            res.push_back(temp[j]);
        }
    }
    return res;
}
void out(vector<vector<int>> &result){
    cout<<"{";
    for(int i=0;i<result.size();i++){
        cout<<"{";
        for(int j=0;j<result[i].size();j++){
            if(j==result[i].size()-1){
                cout<<result[i][j];

            }
            else cout<<result[i][j]<<",";
        }
        if(i==result.size()-1){
             cout<<"}";
        }
        else cout<<"},";
    }
    cout<<"}"<<endl;
}
int main(){
    vector<int> nums = {-1,0,1,2,-1,-4,3,4};
    int target = 0;
    vector<vector<int>> result;
    result = fourSum(nums,target);
    out(result);
}

Python版本

def fourSum(nums,target):
    """
    :param nums: [int]
    :param target: int
    :return: [[int]]
    """
    def threeSum(nums,target):
        res = []
        n = len(nums)
        if n<3: return res
        for i in range(n-2):
            if(nums[i-1] and nums[i-1]==nums[i]): continue
            left = i+1
            right = n-1
            while(left<right):
                sum = nums[i] + nums[left] + nums[right]
                if(sum == target):
                    res.append([nums[i],nums[left],nums[right]])
                    left += 1
                    right -= 1
                elif(sum>target):
                    right -= 1
                else:
                    left += 1
        return res
    result = []
    n = len(nums)
    if(n<4): return result
    nums.sort()
    for i in range(n-3):
        if(nums[i-1] and nums[i-1]==nums[i]):
            continue
        target3 = target - nums[i]
        nums3 = nums[i+1:]
        temp = threeSum(nums3,target3)
        print(temp)
        for t in temp:
            t.append(nums[i])
            result.append(t)
    return result

print(fourSum([-1,0,1,2,-1,-4,3,4],0))

19.删除链表的倒数第N个节点

给定一个链表,删除链表的倒数第n个节点,并且返回链表的头结点。
算法思想:尝试通过构建相差n步的双指针来找到倒数第n+1个节点。

C++版本

struct ListNode{
    int val;
    ListNode* next;
};
ListNode *rmNthnode(ListNode *head,int n){
    if(head==NULL||n<=0) return NULL;
    ListNode *dummy = (ListNode*)malloc(sizeof(ListNode));
    dummy->val = 0;
    dummy->next = head;
    ListNode *start,*end;
    start = dummy;
    end = head;
    for(int i=0;i<n;i++) {
        end = end->next;
    }
    while (end!=NULL) {
        end = end->next;
        start = start->next;
    }
    start->next = start->next->next;
    return head;
}
void printListNode(ListNode *head){
    if(head==NULL) return;
    ListNode *tmp = head;
    while (tmp!=NULL) {
        cout<<tmp->val<<"->";
        tmp = tmp->next;
    }
    cout<<endl;
}
ListNode *createListNode(vector<int> nums){
    ListNode *head,*end,*node;
    head = (ListNode*)malloc(sizeof(ListNode));
    end = head;
    for(int i=0;i<nums.size();i++){
        node = (ListNode*)malloc(sizeof(ListNode));
        node->val = nums[i];
        end->next = node;
        end = node;
    }
    end->next = NULL;
    return head;
}
int main(){
    vector<int> nums= {1,2,3,4,5};
    ListNode *head =createListNode(nums);
    printListNode(head);
    head = rmNthnode(head, 2);
    printListNode(head);
}

Python 版本

"""19.删除链表的倒数第N个节点"""
class ListNode(object):
    def __init__(self,x):
        self.val = x
        self.next = None
class Solution(object):
    def remove_nth_from_end(self,head,n):
        """
        :param head: ListNode
        :param n: int
        :return: ListNode
        """
        dummy = ListNode(-1)
        dummy.next = head
        start = head
        end = dummy
        for i in range(n):
            start = start.next
        while(start):
            start = start.next
            end = end.next
        end.next = end.next.next
        return head

    def printListNode(self,head):
        dummy = head
        while(dummy):
            print(dummy.val,end=",")
            dummy = dummy.next
        print("")
head = ListNode(-1)
a = head.next = ListNode(1)
b = a.next = ListNode(2)
c = b.next = ListNode(3)
d = c.next = ListNode(4)
e = d.next = ListNode(5)
sol = Solution()
sol.printListNode(head)
head = sol.remove_nth_from_end(head,2)
sol.printListNode(head)

20.有效的括号

给定一个只包含’(’,’)’,’[’,’]’,’{’,’}'的字符串,判断字符串是否有效。
算法思想:处理关键点在于右括号,每一个右括号都应该与最近的左括号相对应。

C++版本

bool isValid(string s){
    // map<char,char> m= {{'(',')'},{'[',']'},{{'{','}'}}};
    stack<char> st;
    for(auto ch: s){
        if(ch=='('||ch=='['||ch=='{') {
            st.push(ch);
        }
        else{
            if(st.empty()) return false;
            char ss = st.top();
            if(ss=='('&&ch!=')') return false;
            else if (ss=='['&&ch!=']') return false;
            else if (ss=='{'&&ch!='}') return false;
            st.pop();
        }
    }
    return st.empty();
}
int main(){
    string s1 = "{{}}()";
    string s2 = "[(])";
    cout<<isValid(s1)<<"--"<<isValid(s2)<<endl;
}

Python 版本

def isValid(s):
    """
    :param s: str
    :return: bool
    """
    d = {"(":")","[":"]","{":"}"}
    tmp = ""
    for i in s:
        if i in d.keys():
            tmp += i
        else:
            if tmp=="": return False
            if d[tmp[-1]]!=i: return False
            tmp = tmp[:-1]
    return tmp==""

s1 = "(){}"
s2 = "[(])"
print(isValid(s1))
print(isValid(s2))

本文代码可能有bug,还请各位看官指正,或者小伙伴们有更好的算法,欢迎评论~

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值