剑指offer——字符串

45.把数组排成最小的数

题目

输入一个非负整数数组,把数组里所有数字拼接起来排成一个数,打印能拼接出的所有数字中最小的一个。

解题思路:

此题求拼接起来的最小数字,本质上是一个排序问题。设数组 numsnums 中任意两数字的字符串为 xx 和 yy ,则规定 排序判断规则 为:

若拼接字符串 x + y > y + xx+y>y+x ,则 xx “大于” yy ;
反之,若 x + y < y + xx+y<y+x ,则 xx “小于” yy ;
xx “小于” yy 代表:排序完成后,数组中 xx 应在 yy 左边;“大于” 则反之。

补充:排序算法

插入类排序

直接插入排序

1.示例
在这里插入图片描述
2.算法

 public static void insertSort(int[] a, int length) {
        

        for (i = 1; i < length; i++) {
            temp = a[i]//要进行插入的数据
            j = i-1
            //寻找合适插入位置,大的值向后移动
            while(temp<a[j].key){
                r[j+1]=r[j];
                j=j-1;
            }
            //如找到了一个合适的位置
            r[j+1]=temp;
        }
    }

3.分析

  • 最好的情况是原序列已按关键字大小有序排列,此时需要比较n-1次,移动2(n-1)次。时间复杂度为 O ( n 2 ) O(n^2) O(n2),空间复杂度为 O ( 1 ) O(1) O(1),比较适合数据较少且基本有序的情况。
折半插入排序

1.示例
在这里插入图片描述

2.算法

 
public void binary_insertion_sort(int arr[]) 
{
        int i, j, temp, m, low, high, len = arr.length;
        for (i = 1; i < len; i++)
        {
               temp = arr[i];
               low = 0; high = i-1;
               while (low <= high)
               {
                      m = (low +high) / 2;
                      if(arr[m] > temp)
                               high = m-1;
                      else
                               low = m+1;
               }
         }
         for (j = i-1; j>=high+1; j--)
               arr[j+1] = arr[j];
         arr[j+1] = temp;


3.分析

  • 折半查找只是减少了比较次数,但是元素的移动次数不变。折半插入排序平均时间复杂度为 O ( n 2 ) O(n^2) O(n2);空间复杂度为O(1);是稳定的排序算法。

交换类排序

冒泡排序

1.示例
在这里插入图片描述

2.算法

public class BubbleSort(){
    public void doBubbleSort(int[] array){
        for(int i=0;i<array.length-1;i++){
            for(int j=0;j<array.length-1;j++){
                if(array[j]>array[j+1]{
                    int temp = array[j+1];
                    array[j+1] = array[j];
                    array[j] = temp;
                }
            }
        }
    } 
}

3.分析

时间复杂度为 O ( n 2 ) O(n^2) O(n2);空间复杂度为O(1);是稳定的排序算法。

快速排序

1.示例
在这里插入图片描述

2.算法

public void QKsort(RecordType[] array,int high,int low){
    if(low<high){
        pos = QKpass(r,low,high);
        QKsort(r,low,pos-1);//对左部子表进行排序
        QKsort(r,pos+1,high);//对右部子表进行排序
    }
}
public int QKpass(RecordType[] array,int high,int low){
    x = array[low];//比较基准
    while(low<high){
        while(low<high&&array[high].key>=x.key){
            high--;
        }
        if(low<high){
            array[low]=array[high];
            low++;
        }
        while(low<high&&array[low].key<=x.key){
            low++;
        }
        if(low<high){
            array[high]=array[low];
            high--;
        }
    }
    array[low]=x;
    return low;
}

3.分析

最好的情况是每趟把序列一分两半,时间复杂度为 O ( n l o g 2 n ) O(nlog_2n) O(nlog2n,最坏的情况是已经排好序

选择类排序

简单选择排序

1.示例
在这里插入图片描述

2.算法

public void SelectSort(int[] array){
    for(int i=0;i<array.length;i++){
        k=i
        for(int j=i;j<array.length;j++){
            if array[j]<array[j]{
                k=j:
            }
        }
        int temp = array[i];
        arrat[i]=array[k];
        array[k]=temp;
    }
}

3.分析

最好的情况是已经排序好,则不需要移动记录,但是比较次数和初始排列顺序无关,时间复杂度为 O ( n 2 ) O(n^2) O(n2)

堆排序

1.示例
堆排序描述及算法

3.分析

最坏情况下的时间复杂度为时间复杂度为 O ( n l o g 2 n ) O(nlog_2n) O(nlog2n

58.左旋转字符串

题目

字符串的左旋转操作是把字符串前面的若干个字符转移到字符串的尾部。请定义一个函数实现字符串左旋转操作的功能。比如,输入字符串"abcdefg"和数字2,该函数将返回左旋转两位得到的结果"cdefgab"。

示例 1:

输入: s = “abcdefg”, k = 2
输出: “cdefgab”

题解

1. 切片

substring函数

class solution{
    public String reverseLeftWords(string[] s,int n){
        return s.substring(n)+s.substring(0,n);
    }
}

2.列表遍历拼接
新建一个空的 list(Python)、StringBuilder(Java) ,然后先加入n+1之后的数据,再加入前n个数据

class Solution {
    public String reverseLeftWords(String s, int n) {
        StringBuilder res = new StringBuilder();
        for(int i = n; i < s.length(); i++)
            res.append(s.charAt(i));
        for(int i = 0; i < n; i++)
            res.append(s.charAt(i));
        return res.toString();
    }
}

3.字符串遍历拼接

class Solution {
    public String reverseLeftWords(String s, int n) {
        String res = "";
        for(int i = n; i < s.length(); i++)
            res += s.charAt(i);
        for(int i = 0; i < n; i++)
            res += s.charAt(i);
        return res;
    }
}

补充:字符串遍历,子字符串

  • 获取子字符串:substring(beginIndex,endIndex),截取从第beginIndex个字符到第endIndex个字符,substring(beginIndex),截取从第beginIndex个字符到结束
  • 字符串遍历拼接
 for(int i = 0; i < n; i++)
            res += s.charAt(i);

05 替换空格

题目

请实现一个函数,把字符串 s 中的每个空格替换成"%20"。

题解

  • 字符串
//字符串初始化  
void strInit()  
{  
    cout << "字符串初始化:"  <<endl;  
  
    string s1 = "abcdefg";  //初始化方式1  
    string s2("abcdefg");   //初始化方式2  
    string s3 = s2;         //通过拷贝构造函数 初始化s3  
    string s4(7,'s');       //初始化7个s的字符串  
  
    cout << "s1 = "<< s1 << endl;  
    cout << "s2 = "<< s2 << endl;  
    cout << "s3 = "<< s3 << endl;  
    cout << "s4 = "<< s4 << endl;  
} 

//字符串遍历  
void strErgo()  
{  
    cout << "字符串遍历:"  <<endl;  
  
    string s1 = "abcdefg";  //初始化字符串  
      
    //通过数组方式遍历  
    cout << "1、通过数组方式遍历:"  <<endl;  
    for (int i = 0; i < s1.length(); i++)  
    {  
        cout << s1[i] << " ";  
    }  
    cout << endl;  
  
    //通过迭代器遍历  
    cout << "2、通过迭代器遍历:"  <<endl;  
    for(string::iterator it = s1.begin(); it!= s1.end(); it++)  
    {  
        cout << *it << " ";  
    }  
    cout << endl;  
  
    //通过at()方式遍历  
    cout << "3、通过at()方式遍历:"  <<endl;  
    for (int i = 0; i < s1.length(); i++)  
    {  
        cout << s1.at(i) << " ";        //此方式可以在越界时抛出异常  
    }  
    cout << endl;  
}
  • push_back函数
    -`
    在Vector最后添加一个元素(参数为要插入的值

     //在容器中添加10
    
     int num = 10;
    
     vector<int> vec;
    
     vec.push_back(num);
    

string中最后插入一个字符

    string str;

    str.push_back('d');

类似的

    pop_back() //移除最后一个元素

    clear()  //清空所有元素

    empty() //判断vector是否为空,如果返回true为空

    erase() // 删除指定元素

vector是用数组实现的,每次执行push_back操作,相当于底层的数组实现要重新分配大小(即先free掉原来的存储,后重新malloc)

  • 解题
class Solution {
public:
    string replaceSpace(string s) {
        string array;   //存储结果
        for (int i=0;i<s.length();i++){
	    char c = s.at(i) 
	    if (c==' '){
		    array.push_back('%');
            array.push_back('2');
            array.push_back('0');
	    }
	    else{
		    array.push_back(c)
	    }
    }
return array
    }
};

补充:vector容器添加删除数据

添加元素

  • 方法一
 
 //在指定位置loc前插入值为val的元素,返回指向这个元素的迭代器
iterator insert( iterator loc, const TYPE &val );

 //在指定位置loc前插入num个值为val的元素
void insert( iterator loc, size_type num, const TYPE &val );
 
 //在指定位置loc前插入区间[start, end)的所有元素
void insert( iterator loc, input_iterator start, input_iterator end );

  • 方法二
push_back() 在vector末尾增加元素

删除元素

  • 方法一
    clear() 清空所有元素

    empty() 判断Vector是否为空(返回true时为空)
  • 方法二
erase() 删除指定元素 (可以用指针来代替迭代器)

iterator erase( iterator loc ); //要删除元素的迭代器

iterator erase( iterator start, iterator end ); //要删除的第一个元素的迭代器,要删除的第二个元素的迭代器
  • 方法三
pop_back()移除最后一个元素

58.翻转单词顺序

题目

输入一个英文句子,翻转句子中单词的顺序,但单词内字符的顺序不变。为简单起见,标点符号和普通字母一样处理。例如输入字符串"I am a student. “,则输出"student. a am I”。

解题思路

倒序遍历字符串,每确定一个单词边界,就存储一个单词,最后拼接输出。

class Solution {
    public String reverseWords(String s) {
        s.trim();
        int j = s.length()-1,i=j;//指向最后一个字符
        StringBuilder res = new StringBuilder();
        while(i>=0){ 
            while(i>=0 && s.charAt(i)!=' '){
                i--;
            }
            res.append(s.substring(i+1,j+1)+" ");
            while(i>=0 && s.charAt(i)==' '){
                i--;
            }
            j=i;
        }

        
        return res.toString().trim(); // 转化为字符串并返回
    }
}

首先清空字符串两边多于的空格s.trim()
当字符s.charAt(i)不为空格时,i–向前查找。
截取s.substring(i+1,j+1)
继续向前查找,找单词的末尾,要不断跳过空格,使得j=s.charAt(i),此时s.charAt(i)部位空格。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值