剑指Offer系列题解

链表专题

链表结构体定义:

struct ListNode {
	int val;
	struct ListNode *next;
	ListNode(int x) :
			val(x), next(NULL) {
	}
};

1.链表中倒数第K个结点

倒数第k个结点,从1开始数,倒数第0个结点指针为NULL。

空间复杂度O(n),时间复杂度O(n)解法:

class Solution {
public:
    ListNode* FindKthToTail(ListNode* pListHead, unsigned int k) {
        if(!pListHead) return NULL;
        if(!k) return NULL;
        vector<ListNode*> r;
        ListNode *tmp=pListHead;
        while(tmp){
            r.insert(r.begin(), tmp);
            tmp=tmp->next;
        }
        if(k<=r.size()) return r[k-1];
        else return NULL;
    }
};

倒数第k个就是顺数第n-k+1个(从1开始计数),先遍历得到链表长度n,再找到第n-k+1个结点。
空间复杂度O(1),时间复杂度O(2n-k)解法:

class Solution {
public:
    ListNode* FindKthToTail(ListNode* pListHead, unsigned int k) {
        if(!pListHead || !k) return NULL;
        int len=0; ListNode *p=pListHead;
        while(p) {p=p->next; len++;}
        p=pListHead;
        if(len>=k){
            for(int i=0;i<len-k;i++) p=p->next;
            return p;
        }
        return NULL;
    }
};

找第n-k+1个结点的时间复杂度O(n)解法:

class Solution {
public:
    ListNode* FindKthToTail(ListNode* pListHead, unsigned int k) {
        if(!pListHead || !k) return NULL;
        ListNode *kth=NULL, *p=pListHead;
        int idx=1;
        while(p){
            if(idx==k){
                kth=pListHead; //屏蔽了前k次循环后,剩下每次循环从开头向后移动一个结点
            }
            else if(idx>k){
                kth=kth->next;
            }
            idx++;
            p=p->next;
        }
        return kth;
    }
};

2.反转链表

输入一个链表,反转链表后,输出新链表的表头。

时O(n),空O(1):

class Solution {
public:
    ListNode* ReverseList(ListNode* pHead) {
        ListNode *cur=pHead, *pre=NULL;
        while(cur){
            ListNode *tmp = cur->next;
            cur->next = pre;
            pre = cur;
            cur = tmp;
        }
        return pre;
    }
};

3.从尾到头打印链表

输入一个链表,按链表从尾到头的顺序返回一个ArrayList。

要返回一个ArrayList,所以空间复杂度至少O(n),可以直接使用一个vector,遍历链表每次插入到vector起始位置。

class Solution {
public:
    vector<int> printListFromTailToHead(ListNode* head) {
        vector<int> v;
        while(head){
            v.insert(v.begin(), head->val);
            head = head->next;
        }
        return v;
    }
};

4.合并两个排序的链表

输入两个单调递增的链表,输出两个链表合成后的链表,当然我们需要合成后的链表满足单调不减规则。

设置三个指针a,b,c,分别指向要合并的两个链表和合成的链表,每次将a,b指向的较小的值连接到c上,并将相应的指针后移。

保护原链表版本,空O(n):

class Solution {
public:
    ListNode* Merge(ListNode* A, ListNode* B)
    {
        ListNode *chead = new ListNode(0); //空结点,头指针
        ListNode *c = chead;
        ListNode *a = A;
        ListNode *b = B;
        while(a&&b){
            ListNode *cur;
            if(a->val<=b->val){
                cur = new ListNode(a->val);
                a = a->next;
            }
            else{
                cur = new ListNode(b->val);
                b = b->next;
            }
            c->next = cur;
            c = c->next;
        }
        if(a){
            c->next = a;
        }
        if(b){
            c->next = b;
        }
        return chead->next;
    }
};

不保护原链表版本,空O(1):

class Solution {
public:
    ListNode* Merge(ListNode* A, ListNode* B)
    {
        ListNode *chead = new ListNode(0);
        ListNode *c = chead;
        ListNode *a = A;
        ListNode *b = B;
        while(a&&b){
            ListNode *cur;
            if(a->val<=b->val){
                cur = a;
                a = a->next;
            }
            else{
                cur = b;
                b = b->next;
            }
            c->next = cur;
            c = c->next;
        }
        if(a){
            c->next = a;
        }
        if(b){
            c->next = b;
        }
        return chead->next;
    }
};

5.两个链表的第一个公共结点

输入两个链表,找出它们的第一个公共结点。

与第1题类似,同样可以从链表的长度入手,设长链表长度为L1,短链表长度为L2,可以让长链表指针先走L1-L2步,之后便可以同步走指针了,第一个地址相等的结点就是公共结点了。
时O(2*L1+L2)

class Solution {
public:
    ListNode* FindFirstCommonNode(ListNode* pHead1, ListNode* pHead2) {
        if(!pHead1 || !pHead2)  return NULL;

        ListNode *p1=pHead1, *p2=pHead2;
        int cnt1=0, cnt2=0;
        while(p1) {p1=p1->next; cnt1++;}
        while(p2) {p2=p2->next; cnt2++;}
        p1=pHead1, p2=pHead2;
        if(cnt1<cnt2) {ListNode *tmp=p1; p1=p2; p2=tmp;} //让p1指向长链表

        for(int i=0;i<abs(cnt1-cnt2);i++) p1=p1->next;
        while(p1!=p2){
            p1=p1->next;
            p2=p2->next;
        }
        return p1;
    }
};

一般碰上和长度相关的链表操作,都可以用一些骚操作降低一点时间复杂度,时O(L1+L2)解法:

// 复杂度低,代码又清爽,就是不容易想出来..
class Solution {
public:
    ListNode* FindFirstCommonNode(ListNode* pHead1, ListNode* pHead2) {
        if(pHead1 == NULL || pHead2 == NULL)return NULL;
        ListNode *p1 = pHead1;
        ListNode *p2 = pHead2;
        while(p1!=p2){
            p1 = p1->next;
            p2 = p2->next;
            if(p1 != p2){
                if(p1 == NULL) p1 = pHead2;
                if(p2 == NULL) p2 = pHead1;
            }
        }
        return p1;
    }
};

6.复杂链表的复制

每个结点都有3个域,分别是label数据域、random指针域、next指针域,要求完成对这种类型的链表的完全复制。

时O(n),空O(n):

/*struct RandomListNode {
    int label;
    struct RandomListNode *next, *random;
    RandomListNode(int x) :
            label(x), next(NULL), random(NULL) {
    }
};*/

class Solution {
public:
    map<RandomListNode*, RandomListNode*> mp;

    RandomListNode* copy_(RandomListNode* a)
    {
        if(a==NULL) return NULL;
        if(mp.find(a)==mp.end()){
            RandomListNode *b = new RandomListNode(a->label);
            mp[a]=b;
            return b;
        }
        else return mp[a];
    }

    RandomListNode* Clone(RandomListNode* pHead)
    {
        RandomListNode *newH = NULL;
        RandomListNode *pre = NULL;
        for(RandomListNode *p1=pHead; p1!=NULL; p1=p1->next){
            RandomListNode *p2 = copy_(p1);
            RandomListNode *p2_random = copy_(p1->random);
            p2->random = p2_random;
            if(newH==NULL){
                newH=p2;
                pre=newH;
            }
            else{
                pre->next = p2;
                pre = p2;
            }
        }
        return newH;
    }
};

其他写法:

class Solution
{
public:
    RandomListNode* Clone(RandomListNode* pHead)
    {
        if(pHead == nullptr)
        {
            return nullptr;
        }

        std::unordered_map<RandomListNode*, RandomListNode*> hash_map;

        for (RandomListNode* p = pHead; p != nullptr; p = p->next)
        {
            hash_map[p] = new RandomListNode(p->label);
        }

        for (RandomListNode* p = pHead; p != nullptr; p = p->next)
        {
            hash_map[p]->next = hash_map[p->next];
            hash_map[p]->random = hash_map[p->random];
        }

        return hash_map[pHead];
    }
};

7.删除链表中重复的结点

在一个排序的链表中,存在重复的结点,请删除该链表中重复的结点,重复的结点不保留,返回链表头指针。 例如,链表1->2->3->3->4->4->5 处理后为 1->2->5

错误代码:无法通过的样例{1,1,2,2,3,3},正确输出应为{},下面代码输出{2,2}

class Solution {
public:
    ListNode* deleteDuplication(ListNode* pHead)
    {
        if(!pHead) return pHead;

        ListNode *new_head = pHead;
        if(new_head->next && new_head->val == new_head->next->val){
            int pre_val = new_head->val;
            while(new_head && new_head->val == pre_val){
                new_head = new_head->next;
            }
        }

        if(new_head==NULL) return new_head;

        ListNode *before = new_head;
        ListNode *cur = new_head->next;
        while(cur){
            if(cur->next && cur->next->val==cur->val){
                int _val = cur->val;
                while(cur && cur->val==_val)
                    cur = cur->next;
                before->next = cur;
            }
            else{
                before = cur;
                cur = cur->next;
            }
        }

        return new_head;
    }
};

错误原因:单独拎出了一段重复代码来判断头结点,没有统一代码框架,导致一些细节问题出错。很多情况下统一的逻辑框架可以减少错误的发生。

正确方法:一般来说,当需要一段重复代码来判断头结点时,那么可以在原始头结点之前再加上一个空结点作为辅助,使用一个空的头结点作为before结点,可以统一逻辑框架,避免重复代码。时O(n),空O(1)。

ListNode* deleteDuplication(ListNode* pHead)
{
    ListNode *new_head = new ListNode(0); // 使用空的头结点作为辅助
    new_head->next = pHead;
    ListNode *before = new_head; // 前一个留下来的结点
    ListNode *cur = pHead;
    while(cur){
        if(cur->next && cur->next->val==cur->val){ // 提前预判
            int pre_val = cur->val;
            while(cur && cur->val==pre_val) // 循环里面有cur=cur->next,就要判断cur是否为空
                cur = cur->next;
            before->next = cur;
        }
        else{
            before = cur;
            cur = cur->next;
        }
    }

    return new_head->next; // 返回空的头结点的下一个结点
}

栈与队列专题

1.用两个栈实现队列

class Solution
{
public:
    void push(int node) {
        in.push(node);
    }

    int pop() {
        if(out.empty()){
            while(!in.empty())
                out.push(in.top()), in.pop();
        }
        int t=-1;
        if(!out.empty()){
            t = out.top();
            out.pop();
        }
        return t;
    }

private:
    stack<int> in;
    stack<int> out;
};

字符串专题

1.替换空格

请实现一个函数,将一个字符串中的每个空格替换成“%20”。例如,当字符串为We Are Happy.则经过替换之后的字符串为We%20Are%20Happy。

笔试碰上能用python直接秒:

# -*- coding:utf-8 -*-
class Solution:
    # s 源字符串
    def replaceSpace(self, s):
        # write code here
        s = s.replace(" ", '%20')
        return s
  • 不知道为啥发生段错误的C++代码,时O(n),空O(n):
class Solution {
public:
    void replaceSpace(char *str,int length) {
        if(str==NULL || length<=0)
            return ;

        int num =0;
        for (int i = 0; i < length; i++){
            if (str[i] == ' ')
                num++;
        }
        char *p = (char *)malloc(strlen(str)+1+num*2);
        
        int j=0;
        for(int i=0;i<length;i++) p[j++]=str[i];
        j=0;
        for(int i=0;i<length;i++){
            if(p[i]!=' ')
                str[j++]=p[i];
            else
                str[j++]='%', str[j++]='2', str[j++]='0';
        }
        str[j]='\0';
        free(p);
    }
};

某个小伙伴的时O(n)、空O(1)的做法:
双指针,倒着来

class Solution {
public:
    void replaceSpace(char* str, int length) {
        if(str == NULL || length <0)
            return;
        int num =0;    //空格数目
        for (int i = 0; i < length; i++){
            if (str[i] == ' ')
                num++;
        }
        char* p1 = &str[length -1];//原字符串指针
        char* p2 = &str[length -1 +num*2];//新字符串指针
        for (int i = length-1; i >= 0; i--) {
            if (str[i] == ' ') {
                *p2-- = '0';
                *p2-- = '2';
                *p2-- = '%';
                p1--;
            }else{
                *p2-- = *p1--;
            }
        }
    }
};

二叉树专题

1.重建二叉树

输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建二叉树并返回。

递归解法

  • 时间复杂度
    T ( n ) = 2 T ( n / 2 ) + n T(n)=2T(n/2)+n T(n)=2T(n/2)+n,通过迭代可知 T ( n ) = n l o g n + n T(n)=nlogn+n T(n)=nlogn+n,故时 O ( n l o g n ) O(nlogn) O(nlogn)
  • 空间复杂度
    上限是 S = 2 h ∗ h + 2 h − 1 ∗ ( h − 1 ) + . . . + 2 0 ∗ 0 S=2^h*h+2^{h-1}*(h-1)+...+2^0*0 S=2hh+2h1(h1)+...+200,等差乘等比,先乘 q q q再相减,得 S = O ( n l o g n ) S=O(nlogn) S=O(nlogn),故空 O ( n l o g n ) O(nlogn) O(nlogn)

    可以使用左右边界指针,配合全局vector,或配合常引用vector(传参),使得空间复杂度降到O(1),但可读性没下面的代码好。

/**
 * Definition for binary tree
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
   TreeNode* reConstructBinaryTree(vector<int> pre,vector<int> in)
    {
        if(pre.empty()) return NULL;
        if(pre.size()==1) return new TreeNode(pre[0]);

        TreeNode *root = new TreeNode(pre[0]);
        int ind=-1;
        for(int i=0;i<in.size();i++){
            if(in[i]==root->val){
                ind = i;
                break;
            }
        }

        vector<int> lpre, lin;
        for(int i=0;i<ind;i++) lin.push_back(in[i]);
        for(int i=0;i<ind;i++) lpre.push_back(pre[1+i]);
        root->left = reConstructBinaryTree(lpre, lin);

        vector<int> rpre, rin;
        for(int i=ind+1;i<in.size();i++) rin.push_back(in[i]);
        for(int i=ind+1;i<in.size();i++) rpre.push_back(pre[i]);
        root->right = reConstructBinaryTree(rpre, rin);

        return root;
    }
};

2.二叉搜索树的第k个结点

给定一棵二叉搜索树,请找出其中的第k小的结点。例如, (5,3,7,2,4,6,8) 中,按结点数值大小顺序第三小结点的值为4。

二叉搜索树的中序遍历即为升序序列,于是可以使用中序遍历,遍历到第k个结点后输出。时O(n),空O(1):

/*
struct TreeNode {
    int val;
    struct TreeNode *left;
    struct TreeNode *right;
    TreeNode(int x) :
            val(x), left(NULL), right(NULL) {
    }
};
*/
class Solution {
public:
    int cnt=0;
    int flag=0; //是否已找到
    TreeNode* ans=NULL;
    
    void inOrder(TreeNode *root, int k)
    {
        if(!root) return;
        if(flag) return;
        inOrder(root->left, k);
        cnt++;
        if(cnt==k){
            ans=root;
            flag=1;
        }
        inOrder(root->right, k);
    }
        
    TreeNode* KthNode(TreeNode* pRoot, int k)
    {
        inOrder(pRoot, k);
        return ans;
    }
};

3.平衡二叉树

输入一棵二叉树,判断该二叉树是否是平衡二叉树。
在这里,我们只需要考虑其平衡性,不需要考虑其是不是排序二叉树。

递归计算深度,在计算左右子树的深度的同时判断是否平衡。时O(n),空O(n)(递归深度最大为n)。

class Solution {
public:
    bool balance=true;

    int treeDepth(TreeNode *root)
    {
        if(!root) return 0;
        if(!balance) return -1;
        int ld=treeDepth(root->left);
        int rd=treeDepth(root->right);
        if(abs(ld-rd)>1)
            balance=false;
        return max(ld, rd)+1;
    }

    bool IsBalanced_Solution(TreeNode* pRoot) {
        if(!pRoot) return true;
        treeDepth(pRoot);
        return balance;
    }
};

动态规划(递推)

1.跳台阶

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

状态转移方程:T(n)=T(n-1)+T(n-2),即斐波那契数列,T(n)代表n级台阶的跳法数量。
时O(n),空O(1):

class Solution {
public:
    int jumpFloor(int n) {
        if(n<=0) return 0;
        if(n<=2) return n;
        int a=1, b=2, c;
        for(int i=3;i<=n;i++){
            c=a+b;
            a=b; b=c;
        }
        return c;
    }
};

2.变态跳台阶

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

T(n)=T(n-1)+T(n-2)+…+T(1)+T(0),其中T(1)=T(0)=1,整理后得T(n)=2^(n-1),n>0。
时、空O(1):

class Solution {
public:
    int jumpFloorII(int n) {
        if(n==0) return 0;
        return 1<<(n-1);
    }
};

3.斐波那契数列

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

直接递归会超时,n=39时,计算次数达到63245986,即6e7,在超时的边缘:

int Fibonacci(int n) {
        if(n==0) return 0;
        if(n==1) return 1;
        return Fibonacci(n-1)+Fibonacci(n-2);
}

空间换时间,空O(n),时O(n):

class Solution {
public:
    int ans[50];
    
    void getAns(){
        ans[0]=0; ans[1]=1;
        for(int i=2;i<=39;i++)
            ans[i]=ans[i-1]+ans[i-2];
    }
    
    int Fibonacci(int n) {
        getAns();
        return ans[n];
    }
};

4.矩形覆盖

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

考虑第1块瓷砖(最左边)的放法,第1块瓷砖要么竖着放,要么横着放:若竖着放则后面是一个f(n-1)的子问题,若横着放则第2块瓷砖必须跟着横放在下面,于是接下来是一个f(n-2)的子问题,对第1块瓷砖放法的分类是不重不漏的,所以f(n)=f(n-1)+f(n-2),即斐波那契递推。

时O(n)

class Solution {
public:
    int rectCover(int n) {
        int a=0,b=1,c=0;
        for(int i=0;i<n;i++){
            c=a+b;
            a=b, b=c;
        }
        return c;
    }
};

模拟

1.旋转数组的最小数字

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

时O(n),空O(1):

class Solution {
public:
    int minNumberInRotateArray(vector<int> rotateArray) {
        if(rotateArray.size()==0) return 0;
        int ans=rotateArray[0];
        for(int i=1;i<rotateArray.size();i++){
            int cur=rotateArray[i];
            int pre=rotateArray[i-1];
            if(cur<pre){
                ans=cur;
                break;
            }
        }
        return ans;
    }
};

2.二维数组中的查找

在一个二维数组中(每个一维数组的长度相同),每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。

考虑矩阵左下角的元素,往上递减,往右递增,于是每次当target比左下角的元素小的时候就往上移动一格(当前行可以不用考虑了),target比左下角的元素大的时候就往右移动一格(当前列可以不用考虑了)。
时O(n+m)

class Solution {
public:
    bool Find(int target, vector<vector<int> > a) {
        int n=a.size();
        int m=a[0].size();
        int i=n-1, j=0;
        while(i>=0&&i<n && j>=0&&j<m && a[i][j]!=target){
            if(a[i][j]<target) j++;
            else if(a[i][j]>target) i--;
        }
        if(i>=0&&i<n && j>=0&&j<m) return true;
        else return false;
    }
};

3.二进制中1的个数

输入一个整数,输出该数二进制表示中1的个数。其中负数用补码表示。

n为正数时正常,负数时超时:

int NumberOf1(int n) {
    int cnt=0;
    while(n){
        if(n&1) cnt++;
        n=n>>1;
    }
    return cnt;
}

原因是负数左移1位,最高位自动补1而不是0,于是n为负数时上面的程序会陷入死循环。
测试:

#include <bits/stdc++.h>

using namespace std;

#define ll long long
#define N 1005
#define mod 1000000007
#define INF 0x3f3f3f3f

const double eps=1e-8;
const double pi=acos(-1.0);

//assumes little endian
void printBits(size_t const size, void const * const ptr)
{
    unsigned char *b = (unsigned char*) ptr;
    unsigned char byte;
    int i, j;

    for (i=size-1;i>=0;i--)
    {
        for (j=7;j>=0;j--)
        {
            byte = (b[i] >> j) & 1;
            printf("%u", byte);
        }
    }
    puts("");
}

int main()
{
    int i=-1;
    printBits(sizeof(i), &i);
    int j=i>>1;
    printBits(sizeof(j), &j);
    return 0;
}

输出:

11111111111111111111111111111111
11111111111111111111111111111111

解决:既然给的接口是int,那么可以直接暴力数这32位的二进制数中有多少个1。

int NumberOf1(int n){
    int cnt=0;
    for(int i=0;i<32;i++){ // 每次只检查第i位
        if((n>>i)&1) cnt++;
    }
    return cnt;
}

其他解法:

int NumberOf1(int n) {
	int count = 0;
	while(n!= 0){
		count++;
		n = n & (n - 1); // n-1会把n最右边的1后面的0全部变成1,而原来最右边的1会变成0
		                 // 即从最右边的1开始按位取反,于是n&(n-1)每次把最右边的1变为0
	}
	return count;
} 

4.数值的整数次方

给定一个double类型的浮点数base和int类型的整数exponent。求base的exponent次方。
保证base和exponent不同时为0

注意int可能为负数,O(n)解法:

class Solution {
public:
    double Power(double base, int exponent) {
        int cnt=abs(exponent);
        double ans=1;
        for(int i=0;i<cnt;i++)
            ans*=base;
        if(exponent>=0)
            return ans;
        else
            return 1/ans;
    }
};

快速幂,O(log n):

class Solution {
public:
    double Power(double a, int b){
        int flag=(b>=0?1:0);
        b=abs(b);
        double ans=1;
        while(b){
            if(b&1) ans*=a;
            b=b>>1;
            a=a*a; // 将b看成二进制位,比如2^5,看成2^(101),
                   // b二进制位的相邻位的权重是平方关系
        }
        return flag?ans:1/ans;
    }
};

5.调整数组顺序使奇数位于偶数前面

输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有的奇数位于数组的前半部分,所有的偶数位于数组的后半部分,并保证奇数和奇数,偶数和偶数之间的相对位置不变。

开辟两个vector,遍历原数组,是奇数就放v1,是偶数就放v2,再合并回去,时O(n),空O(n):

class Solution {
public:
    void reOrderArray(vector<int> &a) {
        vector<int> v1,v2;
        for(int i=0;i<a.size();i++){
            if(a[i]&1) v1.push_back(a[i]);
            else v2.push_back(a[i]);
        }
        for(int i=0;i<v1.size();i++) a[i]=v1[i];
        for(int i=v1.size();i<a.size();i++) a[i]=v2[i-v1.size()];
    }
};

利用冒泡排序的思想,时O(n^2),空O(1):

class Solution {
public:
   void reOrderArray(vector<int> &a) {
        for(int i=a.size()-1;i>=0;i--){ // 每次确保第i个位置的元素是偶数(如果偶数没有排完的话)
            int flag=0; // 是否互换过元素
            for(int j=0;j<i;j++){
                if((a[j]&1)==0 && (a[j+1]&1)==1){ // &优先级比==低,需括号!!
                    flag=1;
                    int tmp=a[j];
                    a[j]=a[j+1];
                    a[j+1]=tmp;
                }
            }
            if(!flag) break; // 没有互换过元素则说明偶数已经排完,此时可以直接退出循环
        }
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值