剑指offer-题

有的用php代码实现
1.斐波那契数列 – 面试题9
function fibonaci_1($n){
    if($n < 2){
        return $n == 0 ? 0 : 1;
    }
    return fibonaci_1($n - 1) + fibonaci_1($n - 2);
}
var_dump(fibonaci_1(10));               ///int(55)
var_dump(fibonaci_1(30));               //int(832040)

//斐波那契数列-- 从前来后计算 -- 时间复杂度是O(n)---比递归的效率高
function fibonaci_2($n){
    if($n <= 0){
        return 0;
    }else if($n == 1){
        return 1;
    }
    $num1 = 0;
    $num2 = 1;
    $res = 0;
    for($i = 2; $i <= $n; $i++){
        $res = $num1 + $num2;
        $num1 = $num2;
        $num2 = $res;
    }
    return $res;
}
var_dump(fibonaci_2(30));                 //int(832040)
2.计算二进制中的1的个数 – 面试题10
//计算二进制中的1的个数 1. 判断最后一位是不是1, 如果是 则 统计  如果不是 循环右移一位  ------- 不能有负数,, 否则死循环
function munber_of_1_1($num){
    $count = 0;
    while($num){
        if($num & 1){
            $count ++;
        }
        $num = $num >> 1;
    }
    return $count;
}
var_dump(munber_of_1_1(9));

//2. 将源数据减去一之后 和 源数据与运算 可以将最右边出现的1变成0 比如1100 和 1011 与运算之后就是1000 -- 这个算法比较屌
function number_of_1_2($num){
    $count = 0;
    while($num){
        $count ++;
        $num = $num & ($num - 1);
    }
    return $count;
}
var_dump(number_of_1_2(9));
3.数值的整数次方, 不用内置函数–面试题11
<?php
//实现一个double类型的整数次方, 不能用系统函数 power(double base, int exponent)


//1.利用次方的原理, 有多少个exponent,base就乘几次
function power_1($base, $exponent){
    $res = 1.0;
    for($i = 0; $i < $exponent; $i++){
        $res *= $base;
    }
    return $res;
}
var_dump(power_1(2.2, 2));  //double(4.84)
var_dump(power_1(0.0, 2));  //double(1)
var_dump(power_1(0.0, 0));  //double(0) ---不正确
var_dump(power_1(23.2, -2));  //double(1)    -- 不能处理指数是负数


//2. 加错误处理 如果指数是负数, 先计算正数的,最后在取倒数 但0 没有倒数
function power_2($base, $exponent){
    if($exponent == 0){
        return 0;
    }else if($exponent == 1){
        return 1;
    }
    if(equal($base, 0.0) && $exponent < 0){ //0 没有倒数
        return 0.0;
    }
    $abs_exponent = $exponent;
    if($exponent < 0){                  //指数为负数
        $abs_exponent = -$exponent;
    }
    $res = 1.0;
    for($i = 0; $i < $abs_exponent; $i++){
        $res *= $base;
    }
    if($exponent < 0){      //判断指数是否是负数
        return 1.0 / $res;
    }else{
        return $res;
    }
}
function equal($num1, $num2){   //比较float型, -- 检查是不是 为0
    if(($num1 - $num2 < 0.000001) && ($num1 - $num2 > -0.000001)){
        return true;
    }else{
        return false;
    }
}
var_dump(power_2(2.2, 2));  //double(4.84)
var_dump(power_2(0.0, 2));  //double(0)
var_dump(power_2(0.0, 0));  //int(0)
var_dump(power_2(-2.2, 3));  //double(-10.648)
var_dump(power_2(2.2, -3));  //double(0.093914350112697)
var_dump(power_2(-2.2, -3));  //double(-0.093914350112697)
var_dump(power_2(0.0, -2));  //double(0)


//3.更加高效的方式 比如3^9 = (((3*3)^2)^2)*3     -- 利用递归实现
// a^n --  指数n为偶数 则 计算公式: a^(n/2) * a^(n/2)
//--  指数n为奇数 则 计算公式: a^(n/2) * a^(n/2) * a
function power_3($base, $exponent){
    if($exponent == 0){
        return 1;
    }else if($exponent == 1){
        return $base;
    }
    if(equal($base, 0.0) && $exponent < 0){ //0 没有倒数
        return 0.0;
    }
    $abs_exponent = $exponent;
    if($exponent < 0){                  //指数为负数
        $abs_exponent = -$exponent;
    }
    $res = power_3($base, $abs_exponent >> 1);  // >> 1 相当于/2 效率更高
    $res *= $res;
    if($abs_exponent & 0x1 == 1){        //判断是否是奇数
        $res *= $base;
        if($exponent < 0){              //指数为负数, 最后去倒数
            $res = 1.0 / $res;
        }
    }else{
        if($exponent < 0){
            $res = 1.0 / $res;
        }
    }
    return $res;
}
var_dump(power_3(2.2, 2));  //double(4.84)
var_dump(power_3(0.0, 2));  //double(0)
var_dump(power_3(0.0, 0));  //int(0)
var_dump(power_3(-2.2, 3));  //double(-10.648)
var_dump(power_3(2.2, -3));  //double(0.093914350112697)
var_dump(power_3(-2.2, -3));  //double(-0.093914350112697)
var_dump(power_3(0.0, -2));  //double(0)
var_dump(power_3(4, 34));   //double(2.9514790517935E+20)
?>
4.输入数字n打印 1 到 最大n位十进制数 比如 位数是3 打印1…999 – 面试题12
//输入数字n打印 1 到 最大n位十进制数 比如 位数是3  打印1...999
//1. 考察的知识点: 大数溢出问题, 就是如果用 for循环则 存在大数溢出问题
function print_1_to_max_n_number_1($n){
    if($n <= 0){
        return;
    }
    $number = 1;
    while($n--){
        $number *= 10;
    }
    for($i = 0; $i < $number ;$i++){
        echo $i ,' ';
    }

}
print_1_to_max_n_number_1(3);
//2. 使用数字排列的解法,每一位上都是从0到9进行排列 便是题目的要求  --递归实现
5.在O(1)时间删除链表结点 – 面试题13
//在O(1)时间删除链表结点
//题目: 给定单链表的头指针和一个结点指针, 定义一个函数在O(1)时间删除该结点
//链表的结点定义:
class ListNode{
    public $m_nValue = '';
    public $m_pNext = null;
}
// 由于题目给定了要删除的结点, 所以不用在头部尽心查找了, 但是给定的值要删除的结点所以只能删除结点后的元素(前一个结点没有定位到)
// 删除思想 将删除结点的值设置为删除结点下一个结点的值, 删除结点下一个结点指向下一个结点的结点, 然后删除下一个结点
// 删除有三种情况 1. 链表只有一个结点; 2. 链表有多个结点删除的是未节点; 3. 链表有多个结点删除的是中间结点
function delete_node($node_head, $node_delete){
    if(!$node_head || !$node_delete){
        echo '结点有问题';
        return;
    }
    //第三种情况
    if($node_delete->m_pNext != null){
        $node_delete->m_nValue = $node_delete->m_pNext->m_nValue;
        $node_delete->m_pNext = $node_delete->m_pNext->m_pNext;
        unset($node_delete->m_pNext);
    }
    //第一种情况 --
    else if($node_delete == $node_head){
        unset($node_delete);
        $node_head = null;
    }
    //第二种情况
    else if($node_delete->m_pNext == null){
        $pNode = $node_head;
        //找到$node_delete的前一个结点
        while($pNode->m_pNext != $node_delete){
            $pNode = $pNode->m_pNext;
        }
        unset($node_delete);
        $pNode->m_pNext = null;
    }
}
6.调整数组顺序使奇数位于偶数前面 – 面试题14
//调整数组顺序使奇数位于偶数前面 
#include<iostream>
#define arr_length(arr) (sizeof(arr) / sizeof(arr[0]))
using namespace std;

//1. 定义两个指针, 第一指针指向数组的头部,第二个指向数组的尾部, 判断这两个指针的值
//第一指针判断是否是偶数,第二个指针是否是奇数,如果成立, 则交换位置
void order(int arr[], int len) {
    if(arr == NULL || len <= 0) {
        return ;
    }
    int *begin = arr;
    int *end = &arr[len - 1];
    while(begin < end){
        //begin从前找偶数
        while(begin < end && (*begin & 0x1) != 0) {
            begin ++;
        }
        //end从后找奇数
        while(begin < end && (*end & 0x1) == 0){
            end --;
        } 
        if(begin < end){
            //交换位置
            *begin = (*begin) ^ (*end);
            *end = (*begin) ^ (*end);
            *begin = (*begin) ^ (*end);
        }
    }
}

//上面第一种写法是没有问题的. 但是 面试官如果该题目(比如改成从小到大排序,能被3整除的放在不能被3整除的前面...), 
//则题目需要中while中的判断是需要修改的, 其实面试官想要 面试人 给出一个<模式>,"把已有的解决方案扩展到同类问题上"
//2.传一个回调函数 
void reorder(int arr[], int len, bool (*callback)(int)){
    if(arr == NULL || len <= 0) {
        return ;
    }
    int *begin = arr;
    int *end = &arr[len - 1];
    while(begin < end){
        //begin从前找偶数
        while(begin < end && !callback(*begin)) {
            begin ++;
        }
        //end从后找奇数
        while(begin < end && callback(*begin)){
            end --;
        } 
        if(begin < end){
            //交换位置
            *begin = (*begin) ^ (*end);
            *end = (*begin) ^ (*end);
            *begin = (*begin) ^ (*end);
        }
    }
}
//2.判断是否是偶数 --具体操作 
bool isEvent(int n){
    return (n & 0x1) == 0;
} 
//2.统一的调用接口 
void reorder_event(int arr[], int len){
    reorder(arr, len, isEvent);
    //后面可以添加其他的操作 
}

//输出
int print_arr(int *arr, int len){   
    for(int i = 0; i < len; i++){
        printf("%d ", arr[i]); 
    }printf("\n");
} 
int main(void){
    //1.第一种方式 
    int arr[7] = {1,2,3,4,5,6,7};
    int len = arr_length(arr); 
    order(arr, len);
    print_arr(arr, len);
    //2.第二种方式 
    reorder_event(arr, len);
    print_arr(arr, len);
    return 0;
}
7.求链表中倒数第k个结点 – 面试题15
/*
    求链表中倒数第k个结点
    -------------------------------
    思想一: 因为是倒数的, 所以从后来前遍历即可, 但是单链表中不能从后来前遍历,所以要从头结点到n-k+1处 就是倒数k的结点
    需要遍历链表两次,不是最好的解法
    -------------------------------
    思想二: 如果实现遍历一次链表就能找出倒数k的结点,可以定义两个指针,第一指针先走 
    第一指针从头结点开始- 一直遍历到k处[从1到n 如果是从0开始,则遍历到k-1出] 后 第二个指针再从头结点 开始遍历 -- 之后两个结点同时遍历链表 
    当第一结点走到链表尾的时候,第二个结点就是倒数第k个结点 
*/
#include<iostream>
using namespace std;

typedef int ElemType;
typedef int Status;

typedef struct Node{
    ElemType data;

    struct Node *next; 
} Node;
typedef struct Node *LinkList;

//查找方法 结果用node返回 -- index 不能小于0 也不能大于链表长度 
Status find_to_tail(LinkList p_head, int index, LinkList *node){
    if(index < 0 || p_head == NULL){
        return 0;
    }
    LinkList p_first = p_head;
    LinkList p_last = NULL;
    for(int i = 0; i < index; i++){
        p_first = p_first->next;
        if(p_first == NULL){
            printf("查找位置不正确\n");
            return 0;
        } 
    }
    p_last = p_head;
    while(p_first != NULL){
        p_first = p_first->next;
        p_last = p_last->next; 
    }
    (*node) =  p_last;  
    return 1; 
} 

//遍历链表
void list_traverse(LinkList p_head){
    if(p_head == NULL){
        return;
    }
    LinkList p = p_head->next;
    while(p != NULL) {
        printf("%d ", p->data);
        p = p->next;
    }
    printf("\n"); 
}

//初始化链表 -- 生成10个结点 
void init_list(LinkList *p_head){
    if(p_head == NULL){
        return;
    }
    int num = 10; 
    LinkList p, new_node;
    p = *(p_head);
    while(num > 0){
        new_node = new Node;
        new_node->data = num;
        p->next = new_node;
        p = new_node;
        num --; 
    }
    p->next = NULL;
} 

int main(void){
    LinkList List, node;    
    init_list(&List);
    int option = 1;
    printf("\n 1. 遍历\n 2. 查找\n 0. 退出\n");
    while(1){
        scanf("%d", &option);
        switch(option){
            case 1:
                list_traverse(List);
                break;
            case 2:
                printf("倒数查找请输入查找位置\n");
                scanf("%d", &option);
                option = find_to_tail(List, option, &node);
                if(option){
                    printf("%d \n", node->data);                        
                }
                break;
            case 0:
                return 0;
            default:
                 printf("\n 1. 遍历\n 2. 查找\n 0. 退出\n");
                 break;
        }
    } 
    return 0;
} 
8.翻转链表 – 面试题16
/*
    翻转链表
    ------------------
    题目: 定义一个函数,输入一个链表的头结点, 翻转链表并输出翻转后链表的头结点
    ------------------
    思想: 利用3个指针, 分别指向当前遍历的结点,它的前一个结点, 它的后一个结点 
    -----------------
    list_reverse()实现 
*/
#include<iostream>
#include<stdlib.h>
using namespace std;


typedef int ElemType;
typedef int Status;

typedef struct Node{
    ElemType data;

    struct Node *next; 
} Node;
typedef struct Node *LinkList;


//翻转链表函数 用root 返回翻转后的头结点 
Status list_reverse(LinkList *p_head, LinkList *root){
    if(p_head == NULL){
        printf("参数不合法"); 
        return 0;    
    }
    LinkList p_first = NULL;
    LinkList p_current = (*p_head)->next;       //头结点 
    LinkList p_last = NULL;
    while(p_current != NULL){
        p_last = p_current->next;
        p_current->next = p_first;
        if(p_last == NULL){
            (*root) = p_current;
            (*p_head) = (LinkList) malloc(sizeof(Node));    
            (*p_head)->next = p_current; 
            return 1; 
        }
        p_first = p_current;
        p_current = p_last;
    }       
} 


//遍历链表
void list_traverse(LinkList p_head){
    if(p_head->next == NULL){
        return;
    }
    LinkList p = p_head->next;
    while(p != NULL) {
        printf("%d ", p->data);
        p = p->next;
    }
    printf("\n"); 
}

//初始化链表 -- 生成10个结点 
void init_list(LinkList *p_head){
    if(p_head == NULL){
        return;
    }
    int num = 10; 
    LinkList p, new_node;
    *p_head = new Node;     //定义一个头结点 
    p = *p_head;
    while(num > 0){
        new_node = new Node;
        new_node->data = num;
        p->next = new_node;
        p = new_node;
        num --; 
    }
    p->next = NULL;
} 

int main(void){
    LinkList List, node;    
    init_list(&List);
    int option = 1;
    printf("\n 1. 遍历\n 2. 翻转链表\n 0. 退出\n");
    while(1){
        scanf("%d", &option);
        switch(option){
            case 1:
                list_traverse(List);
                break;
            case 2:
                printf("翻转链表之后的值:\n");              
                option = list_reverse(&List, &node);
                if(option){
                    printf("%d \n", node->data);                        
                }
                break;
            case 0:
                return 0;
            default:
                 printf("\n 1. 遍历\n 2. 查找\n 0. 退出\n");
                 break;
        }
    } 
    return 0;
} 
9.合并两个链表 – 面试题17
/*
    合并两个排序的链表 
    --------------
    合并两个已经有序的链表--生成一个新的链表 
    结果是按照有序的结果(递增排序) 
    --------------
    因为是产生了一个新的链表, 所以 可以使用递归的思想, 
    当第一个链表小于第二个链表, 就将第一链表的头结点赋给新的链表, 否则,第二个链表的头结点赋值给新的链表 ---一直这样
    merge()函数实现 
    -------------
    如果不产生, 可以使用借助一个指针, 标记头结点小的next指针 
*/
#include<iostream>
using namespace std;

typedef int ElemType;
typedef int Status;

typedef struct Node{
    ElemType data;

    struct Node *next; 
} Node;
typedef struct Node *LinkList;

//合并链表 -- 结果返回到 p_head3 
LinkList merge(LinkList p_head1, LinkList p_head2){
    //判断两个链表是否为null, 如果是null, 则返回 另一个链表 
    if(p_head1 == NULL){
        return p_head2;
    } else if(p_head2 == NULL){
        return p_head1;
    }
    LinkList p_head3 = NULL;
    LinkList p1 = p_head1, p2 = p_head2;
    if(p1->data > p2->data){
        p_head3 = p2;
        p_head3->next = merge(p1, p2->next);
    }else{
        p_head3 = p1;
        p_head3->next = merge(p1->next, p2);
    }
    return p_head3; 
} 

//遍历链表
void list_traverse(LinkList p_head){
    if(p_head == NULL){
        return;
    }
    LinkList p = p_head->next;
    while(p != NULL) {
        printf("%d ", p->data);
        p = p->next;
    }
    printf("\n"); 
}

//初始化第一个链表  -- 生成10个结点 
void init_list(LinkList *p_head){
    if(p_head == NULL){
        return;
    }
    int num = 10; 
    LinkList p, new_node;
    p = *(p_head);
    for(int i = 0; i < num; i++){
        new_node = new Node;
        new_node->data = i;
        p->next = new_node;
        p = new_node;
    }
    p->next = NULL;
} 

//初始化第二个链表  -- 生成10个结点 
void init_list2(LinkList *p_head){
    if(p_head == NULL){
        return;
    }
    int num = 20; 
    LinkList p, new_node;
    p = *(p_head);
    for(int i = 0; i < num; i += 2){
        new_node = new Node;
        new_node->data = i;
        p->next = new_node;
        p = new_node;
    }   
    p->next = NULL;
} 
int main(void){
    LinkList List1, List2, List3, node; 
    init_list(&List1);  
    init_list2(&List2); 
    printf("遍历链表1的结果: \n");
    list_traverse(List1);
    printf("遍历链表2的结果: \n");
    list_traverse(List2);
    printf("遍历合并链表后的结果: \n");
    list_traverse(merge(List1->next, List2->next));
    return 0;
} 
10.数组中超过一半的数字 – 面试题29
/*
    数组中,有一个数字出现的次数超过数组长度的一半,找出来.    
    ---------------------
    1. 因为数字出现的次数会超过数组长度的一半,所以给数组排序之后, 中间的数就是超出数组一半的数
    2. 和一相同, 采用一个计数器, 一个参考值, 如果相同,计数器加一,否则计数器减一,最后计数器大于1的那个数就是要找的数
    --------------------
    采用第二种方式 
*/ 
#include<iostream>
using namespace std;

//判断数组的合法性 
bool check_array(int *arr, int length){
    if(arr == NULL || length <= 0){
        return false;
    }
    return true;
}

//找出超过一半的数字 
int more_half_num(int *num, int length){
    if(!check_array(num, length)){
        return 0;
    }
    int result = num[0];        //参考值 
    int times = 1;              //计数器 
    for(int i = 1; i < length; i++){
        if(result == num[i]){
            times++;
        }else if(result != num[i]){
            times--;
        }
        if(times == 0){
            result = num[i];
            times = 1;
        }
    }   
    return result;
}
int main(void){
    int arr[9] = {1,2,3,2,2,2,5,4,2};
    int res = more_half_num(arr, 9);
    printf("数组中出现次数最多的元素是: %d ", res);
    return 0;
}
11.连续子数组中的最大和 – 面试题31
/*
    连续子数组中的最大和
    输入一个整形的数组,其中有整数也有负数,求数组中一个或者连续的多个整数组成的一个子数组.时间复杂度是O(n)
    --------------------
    1.采用分析数组规律, 当累加数组中出现负数,则从后一位开始计算,每一次累加的数和上次累加的数比较,将最大值保留起来 

*/
#include<iostream>
using namespace std;

//求连续子数组中的最大和
int sub_array_sum(int *arr, int length){
    if(arr == NULL || length <= 0){
        return 0;
    }
    int current_sum = 0;        //每次累加的数,存放位置 
    int current_sum_max = 0;    //存放最大值 
    for(int i = 0; i < length; i++){
        if(current_sum <= 0){   //前面的数组元素之和小于0 则从当前元素开始计算 
            current_sum = arr[i];
        }else{
            current_sum += arr[i];  //累加计数 
        }       
        if(current_sum > current_sum_max){
            current_sum_max = current_sum;  //存放最大值 
        }
    }
    return current_sum_max;
}

int main(void){
    int arr[8] = {1,-2,3,10,-4,7,2,-5} ;
    int res = sub_array_sum(arr, 8);
    printf("连续子数组中的最大和是: %d ", res);
    return 0;
} 
12.求最小于k个数 – 面试题30
//求最小于k个数-- 基于快排的思想
int partition(int arr[], int start, int end){
    int low = start;
    int high = end;
    int temp = arr[low];
    while(high > low){
        while(high > low && arr[high] >= temp){
            high --;
        }
        arr[low] = arr[high];
        while(high > low && arr[low] <= temp){
            low++;
        }
        arr[high] = arr[low];
    }
    arr[low] = temp;
    return low;
}
void get_last_num(int arr[], int len, int num){
    if(NULL == arr || len <= 0 || num <= 0){
        return;
    }
    int start = 0;
    int end = len - 1;
    int index = partition(arr, start, end);
    while(index != num - 1){//index== num-1表示前面num个是最小值 
        if(index > num - 1){
            end = index - 1;
        }
        else{
            start = index + 1;
        }
        index = partition(arr, start, end);
    }

    for(int i = 0; i < num; i++){
        printf("%d ", arr[i]);
    }
} 
13. 句子翻转 – I am student 反转为 student am I

思想, 先对单词翻转, 最后在整体翻转

#include<iostream>
#include<string.h>
using namespace std;

//字符串的翻转 -- I am student 反转为  student am I
/*
    思想, 先对单词翻转, 最后在整体翻转 
*/ 
void reve_change(char *start, char *end) {
    if(start == NULL || end == NULL){
        return ;
    }
    char temp;
    while(start < end){
        temp = *start;
        *start = *end;
        *end = temp;
        start ++;
        end --;
    }
}
char *reve_sentence(char *str){
    if(str == NULL || strlen(str) == 0){
        return str;
    }
    int len = strlen(str);
    char *pre = str;
    char *p_cur;
    p_cur = strchr(pre, ' ') ;
    if(p_cur == NULL){
        return str;
    }
    while(p_cur = strchr(pre, ' ')){
        reve_change(pre, p_cur - 1) ;
        pre = p_cur + 1;
    }
    p_cur = str + len - 1;
    reve_change(pre, p_cur);
    reve_change(str, p_cur);
    return str;
}

int main(void){ 
    char string[] = "I am a student";
    cout << reve_sentence(string);
    return 0;
}
14. 字符串前面n个字符放到后面 – abcdef 前三个放到后为 defabc

思想: 1. 前n个字符翻转, 2. 后面的字符翻转, 3. 整体翻转

void reve_change(char *start, char *end) {
    if(start == NULL || end == NULL){
        return ;
    }
    char temp;
    while(start < end){
        temp = *start;
        *start = *end;
        *end = temp;
        start ++;
        end --;
    }
}
//字符串前面n个字符放到后面
char *str_reve(char *str, int n){
    if(NULL == str || strlen(str) == 0){
        return str;
    }
    int len = strlen(str);
    if(n <= 0 || n >= len){
        return str;
    }
    reve_change(str, str + n - 1);
    reve_change(str + n, str + len - 1);
    reve_change(str, str + len - 1);
    return str;
}
int main(void){ 
    char string[] = "I am a student";
    cout << str_reve(string, 4);
    return 0;
}
15. 实现一个函数,对一个正整数n,算得到1需要的最少操作次数。操作规则为:如果n为偶数,将其除以2;如果n为奇数,可以加1或减1;一直处理下去

分析: 奇数的时候加1或减1,完全取决于二进制的后两位,如果后两位是10、00那么肯定是偶数,选择除以2,如果后两位是01、11,那么选择结果会不一样的,如果是*****01,那么选择减1,如果是*****11,那么选择加1,特殊情况是就是n是3的时候,选择减1操作

//递归实现
int func(int n){
    if(n == 1){
        return 0;
    }
    if(n & 0x1) == 0){
        return 1 + func(n / 2);
    }
    if(n == 3){
        return 2;
    }
    if(n & 0x2){
        return 1 + func(n + 1);
    }else{
        return 1 + func(n - 1);
    }
}

//非递归实现
int func(int n){
    int count = 0;
    while(n > 1){
        if(n % 2 == 0){
            n >>= 1;
        }else if(n == 3){
            n --;
        }else{
            if(n & 0x2){
                n++;
            }else{
                n--;
            }
        }
        count++;
    }
    return count;
}
16. 消除嵌套的括号

例如 输入 (1,2,3,(2,3),(3,3)), 则输出(1,2,3,2,3,3,3)

//验证字符串是否是合法的
bool is_valid(char *str) {
    if(NULL == str){
        return false;
    }
    stack<char>stack;   
    while('\0' != *str){
        if('(' == *str){
            stack.push(*str++);
        }else if(')' == *str){
            if(stack.empty()){
                return false;
            }else{
                stack.pop();
                str++;
            }
        }else{
            str++;
        }
    }
    if(stack.empty()){
        return true;
    }else{
        return false;
    }
}
//消去中间的括号
char *elem_back(char *str) {
    if(NULL == str){
        return str;
    }
    char *temp = new char[strlen(str) + 1];
    char *result = temp;
    *temp++ = *str++;
    while('\0' !=  *str){
        if('(' == *str || ')' == *str){
            str++;
            continue;
        }
        *temp++ = *str++;
    }
    *temp++ = ')';
    *temp = '\0';
    return result;
}
int main(void){ 
    char arr_temp[] = "(1,2,3,(2,3),(3,3))";
    if(is_valid(arr_temp)){
        cout << elem_back(arr_temp);        
    }
    return 0;   
}
17. 求两个有序数组的交集

时间复杂度为O(N+M)
先判断两个数组的首元素是否相等, 如果相等则输出, 不相等,小的则相应的数组指针后移,直到坐标超过数组的范围

//两个有序数组的交集
void inter_array(int arr1[], int arr1_len, int arr2[], int arr2_len) {
    if(NULL == arr1 || NULL == arr2 || 0 >= arr1_len || 0 >= arr2_len){
        return;
    }
    int index_arr1, index_arr2;
    index_arr1 = index_arr2 = 0;
    while(index_arr1 < arr1_len && index_arr2 < arr2_len){
        if(arr1[index_arr1] == arr2[index_arr2]){
            cout << arr1[index_arr1] << " ";
            index_arr1 ++;
            index_arr2 ++;
        }else if(arr1[index_arr1] < arr2[index_arr2]){
            index_arr1 ++; 
        }else{
            index_arr2 ++;
        }
    }
}
18. 约瑟夫环
int huan(int arr[], int len, int k){
    int count = 0;
    int i = 0;
    int len_of_o = len;
    while(len_of_o != 0){
        if(arr[i % len] != -1) {
            count ++;
        }
        if(count == 3){
            arr[i % len] = -1;
            len_of_o --;
            count = 0;
        }else{
            i++; 
        }
        if(len_of_o == 1){
            if(arr[i % len] != -1) {
                return (i % len);
            }
        }
    }
} 
int main(void){
    int arr6[7] = {0,0,0,0,0,0,0};
    cout << huan(arr6, 7,3);
    return 0;
}
//php
//约瑟夫环
function ring($arr, $m){
    if(empty($arr) || 0 == $m){
        return -1;
    }
    $len = count($arr);
    $index = 0;
    while($len != 1){
        $index ++;
        $header = array_shift($arr);
        if($index % $m != 0){
            array_push($arr, $header);
        }else{
            $len --;
        }
    }
    return $arr[0];
}
$arr = [1,2,3,4,5,6];
var_dump(ring($arr, 3));
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值