算法学习

1.逆波兰算法

题目:

求["2", "1", "+", "3", "*"];

前置知识:

(1)在求解逆波兰算法前,需要先了解四则运算的表达式,四则运算的表达式分3中:前缀表达式(又称波兰表达式)、中缀表达式、后缀表达(又称逆波兰表达式);

以上三种表达式是等价的。

(2)栈:栈是先入后出的,所以,这里可以借用栈的思路来解题。

解题思路:

(1)遍历数组;

(2)遇到数字,直接入栈;

(3)遇到符号:

  • 弹出栈顶的右操作数
  • 弹出栈顶的左操作数
  • 使用符号进行计算,将计算的结果放入栈中

(4)最后栈中的唯一数字就是后缀表达式计算的值。

代码实现:

因为OC没有用直接可用的栈代码,有两种方式来手动模拟栈的操作:

(1)用代码实现一个栈的功能,可参考如下链接:https://www.jianshu.com/p/0ae0310e0263

(2)用数组模拟栈的操作。

目前只是用数组来模拟栈的操作,代码如下:

- (void)reverseTest:(NSArray *)array {
    //逆波兰,算出下列的值: [2 1 + 3 *]
    NSMutableArray *stackArray = [NSMutableArray array];
    for (NSString *object in array) {
        if ([self isOperator:object]) {
            //取出栈顶的值 操作
            NSString *right = stackArray.lastObject;
            [stackArray removeLastObject];
            NSString *left = stackArray.lastObject;
            [stackArray removeLastObject];
            NSInteger caclulate = [self caclulateWithLeft:[left intValue] right:[right integerValue] opertator:object];
            [stackArray addObject:[NSString stringWithFormat:@"%ld", caclulate]];
        }else {
            //如果是数字,就存入栈中
            [stackArray addObject:object];
        }
    }
    NSLog(@"%@", stackArray.lastObject);
}

- (BOOL)isOperator:(NSString *)object {
    return [@"+-*/" containsString:object];
}

- (NSInteger)caclulateWithLeft:(NSInteger)left right:(NSInteger)right opertator:(NSString *)operator{
    if ([operator isEqualToString:@"+"]) {
        return left + right;
    }
    if ([operator isEqualToString:@"-"]) {
        return left - right;
    }
    if ([operator isEqualToString:@"*"]) {
        return left * right;
    }
    if ([operator isEqualToString:@"/"]) {
        return left / right;
    }
    return 0;
}

2.合并两个有序列表

题目:

前置知识:

链表(Linked List)是一种物理存储单元上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的,表现形式如下图所示:

iOS没有现成的链表结构,如果需要的话,需要自己代码实现。

解题思路:

这个思路不太好说,一切尽在代码中吧

代码实现:

新建一个链表:
#import <Foundation/Foundation.h>

NS_ASSUME_NONNULL_BEGIN

@interface LYZLinkNode : NSObject

@property (nonatomic, copy) NSString * key;

@property (nonatomic, strong) LYZLinkNode * next ;

@end


实现:
- (LYZLinkNode *)merginLinkerWithNode1:(LYZLinkNode *)node1 node2:(LYZLinkNode *)node2 {
    if (node1 ==  nil) return node2;
    if (node2 == nil)  return node1;
    
    LYZLinkNode *head = [[LYZLinkNode alloc] init];
    if ([node1.key intValue] < [node2.key intValue]) {
        head = node1;
        node1 = node1.next;
    }else {
        head = node2;
        node2 = node2.next;
    }
    
    LYZLinkNode *currentNode = head;
    while (node1 != nil && node2 != nil) {
        if ([node1.key intValue] <= [node2.key intValue]) {
            currentNode = currentNode.next = node1;
            node1 = node1.next;
        }else {
            currentNode = currentNode.next = node2;
            node2 = node2.next;
        }
    }
    if (node1 == nil) {
        currentNode = currentNode.next = node2;
    }
    if (node2 == nil) {
        currentNode = currentNode.next = node1;
    }
    return head;
}

3.合并K个有序链表

这个是在上一个算法题的前提下继续研究的。解题思路有多重,目前,我只实现了三种:

第一种:两两合并

/** 合并k个有序链表---两两合并 */
- (LYZLinkNode *)merginKLinkedWithArray:(NSArray *)array {
    NSMutableArray *nodeArray = [NSMutableArray arrayWithArray:array];
    
    for (NSInteger i = 1; i < nodeArray.count; i++) {
        LYZLinkNode *node = [self merginLinkerWithNode1:nodeArray[0] node2:nodeArray[i]];
        [nodeArray replaceObjectAtIndex:0 withObject:node];
    }
    return nodeArray[0];
}

第二种:最小堆顶

思路:把链表加入数组中,在数组中把最小值弹出,并把最小值的next值加入数组中

/** 合并k个有序链表---最小堆顶 */
- (LYZLinkNode *)merginKLinkedWithMiniStackTop:(NSArray *)array {
    LYZLinkNode *node = [[LYZLinkNode alloc] init];
    LYZLinkNode *current = node;
    NSMutableArray *arrayM = [NSMutableArray arrayWithArray:array];
    int first = -1;
    while (true) {
        arrayM =  [[arrayM sortedArrayUsingComparator:^NSComparisonResult(id  _Nonnull obj1, id  _Nonnull obj2) {
            return [self compare:obj1 node2:obj2];
        }] mutableCopy] ;
        LYZLinkNode *n1 = arrayM[0];
        if (first == -1) {
            current = node = n1;
            first = 1;
            [arrayM replaceObjectAtIndex:0 withObject:current.next];
        }else {
            if (n1.next == nil) {
                current = current.next = n1 ;
                [arrayM removeObjectAtIndex:0];
            }else {
                current = current.next = n1 ;
                [arrayM replaceObjectAtIndex:0 withObject:n1.next];
            }
        }
        if (arrayM.count == 0) {
            break;
        }
    }
    return node;
}

- (NSComparisonResult)compare:(LYZLinkNode *)node1 node2:(LYZLinkNode *)node2 {
    NSInteger key1 = [node1.key integerValue];
    NSInteger key2 = [node2.key integerValue];
    if (key1 == key2) {
        return NSOrderedSame;
    }
    if (key1 > key2) {
        return NSOrderedDescending;
    }
    return NSOrderedAscending;
}

第三种:分治策略

如上图可见:把两个链表合并并赋值给第一个链表

/** 合并k个有序链表--分治策略  */
- (LYZLinkNode *)merginKLinkenWithFenZhiCeLue:(NSArray *)array {
    if (array.count == 0) {
        return nil;
    }
    int step = 1;
    while (step < array.count) {
        for (NSInteger i = 0; i < array.count; i += 2*step) {
            if (i+1 >= array.count) {
                break;
            }
           [self merginLinkerWithNode1:array[i] node2:array[i+step]] ;
        }
        step *= 2;
    }
    return array[0];
}

4.验证二叉搜索树

题目:

给定一个二叉树,判断其是否是有效的二叉搜索树

前置知识:

先序遍历:先访问根节点,再先序遍历左子树,最后先序遍历右子树;

中序遍历:先中序遍历左子树,再访问根节点,最后中序遍历右子树;

后序遍历:先后序遍历左子树,再后序遍历右子树,最后访问根节点。

解题思路:

递归思路

代码实现:

方法一:

方法二:

 

5.二叉树中的最大路径和

题目:

实例:

解题思路:

代码实现:

创建一个二叉树的类:
------.h-----
@interface LYZTreeNode : NSObject

@property (nonatomic, assign) int value ;
@property (nonatomic, strong) LYZTreeNode * leftNode ;
@property (nonatomic, strong) LYZTreeNode * rightNode ;

- (void)treeNodeWithValue:(int)value left:(LYZTreeNode *)left right:(LYZTreeNode *)right;

@end

------.m-------
@implementation LYZTreeNode

- (void)treeNodeWithValue:(int)value left:(LYZTreeNode *)left right:(LYZTreeNode *)right {
    self.value = value;
    self.leftNode = left;
    self.rightNode = right;
}

@end


/----------实现--------/

int sum = 0;
- (int)treeNodeValue:(LYZTreeNode *)node {
    if (node == nil) {
        return 0;
    }
    
    int leftValue = MAX([self treeNodeValue:node.leftNode], 0);
    int rightValue = MAX([self treeNodeValue:node.rightNode], 0);
    sum = MAX(leftValue + node.value + rightValue, sum);
    return MAX(MAX(leftValue, rightValue) + node.value, 0) ;
}

6.二叉树展开为链表

题目:

解题思路:

方法一:先序遍历

(1)把右节点用单独的变量A存储;

(2)把左节点赋值给二叉树的右节点;把左节点清空

(3)把右节点变量A赋值给当前二叉树的最后遍历到的右节点

(4)遍历右节点,重复上面的步骤。

方法二:后续遍历

(1)遍历二叉树的右节点;

(2)编辑二叉树的左节点;

(3)把上一次遍历到的节点赋值给二叉树的右节点

(4)清空左节点;

代码实现:

方法一:

- (void)qianXuPreView:(LYZTreeNode *)node {
    if (node == nil) {
        return;
    }

    LYZTreeNode *oldRightNode = node.rightNode;
    node.rightNode = node.leftNode;
    node.leftNode = nil;
    
    LYZTreeNode *rootNode = node;
    while (rootNode.rightNode != nil) {
        rootNode = rootNode.rightNode;
    }
    rootNode.rightNode = oldRightNode;
    [self qianXuPreView:node.rightNode];
}

方法二:

- (void)houXuPreView:(LYZTreeNode *)node {
    if (node == nil) {
        return;
    }
    [self houXuPreView:node.rightNode];
    [self houXuPreView:node.leftNode];
    
    if (self.preView != nil) {
        node.rightNode = self.preView;
        node.leftNode = nil;
    }
    self.preView = node;
}

 7. 打家劫舍

题目:

你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的
房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。

给定一个代表每个房屋存放金额的非负整数数组,计算你在不触动警报装置的情况下,能够偷窃到的最高金额。

示例 1:

输入: [1,2,3,1]
输出: 4
解释: 偷窃 1 号房屋 (金额 = 1) ,然后偷窃 3 号房屋 (金额 = 3)。
     偷窃到的最高金额 = 1 + 3 = 4 。
示例 2:

输入: [2,7,9,3,1]
输出: 12
解释: 偷窃 1 号房屋 (金额 = 2), 偷窃 3 号房屋 (金额 = 9),接着偷窃 5 号房屋 (金额 = 1)。
     偷窃到的最高金额 = 2 + 9 + 1 = 12 。

解题思路:

方法一:递归的思想

 [1, 2, 3, 4, 5, 6]

 第一步:

 如果第一家打劫的话,只能从[3, 4, 5, 6]家中打劫出最多的钱

 如果第一家不打劫的话,就从[2, 3, 4, 5, 6]家中打劫出最大的钱

 第二步:

 如果打劫第一家了,那么[3, 4, 5, 6]最大的打劫金额 按照第一步的思路来计算

    如果打劫了3这一家,那么就从[5, 6]家中打劫出最多的钱

    如果不打劫3这一家,那么就从[4, 5, 6]家中打劫出最多的钱

 如果不打劫第一家,那么[2, 3, 4, 5, 6]最大的打劫金额 也按照第一步的思路来计算

    如果打劫2这一家,那么就从[4, 5, 6]中打劫出最多的钱

    如果不打劫2这一家,那么就从[3, 4, 5, 6]中打劫出最多的钱

 第三步:

如果打劫了3这一家,那么[5, 6]家中打劫最大的钱就是max(5,6)

如果不打劫3这一家,那么[4, 5, 6]家打劫出最大的钱,按照第一步的思路计算....

方法二:非递归思想

自定义一个数组,这个数组存放的是每一家能打劫出来的最多的钱的值

每一家能打劫出来的值就是 max( 自己这一家的钱 + 上上一家可能打劫出来最大的钱, 上一家能打劫出来的最大的值)

代码实现:

方法一:

- (int)rob:(NSArray *)array begin:(int)begin {
    if (begin == array.count - 1) {
        return [array[begin] intValue];
    }
    if (begin == array.count - 2) {
        return MAX([array[begin] intValue], [array[begin + 1] intValue]) ;
    }
    
    int robFirst = [array[begin] intValue] + [self rob:array begin:begin + 2];
    int robSecond = [self rob:array begin:begin + 1];

    return MAX(robFirst, robSecond);
}

-----调用-----
NSArray *array = @[@"1", @"3", @"5", @"8", @"4", @"11"];
NSLog(@"rob = %d", [self robWithoutArray:array]);

方法二:

- (int)rob:(NSArray *)array {
    if (array.count == 1) {
        return [array[0] intValue];
    }
    NSMutableArray *valueArray = [NSMutableArray array];
    valueArray[0] = array[0];
    valueArray[1] = array[1];
    for (int i = 2; i < array.count; i++) {
        NSInteger maxValue = MAX([array[i] integerValue] + [valueArray[i - 2] integerValue], [valueArray[i - 1] integerValue]);
        valueArray[i] = [NSString stringWithFormat:@"%ld", maxValue];
    }
    return [valueArray[array.count - 1] intValue];
}

优化第二种的方法:

- (int)robWithoutArray:(NSArray *)array {
    if (array.count == 1) {
        return [array[0] intValue];
    }
    
    int firstValue = [array[0] intValue];
    int secondValue = [array[1] intValue];
    int tem ;
    for (int i = 2; i < array.count; i++) {
        tem = MAX([array[i] intValue] + firstValue, secondValue);
        firstValue = secondValue;
        secondValue = tem;
    }
    return secondValue;
}

8.取前K个高频数

题目:

思路:

1.遍历数组,以出现的值为key,出现的次数为Value,保存到一个字典中;

2.利用散列表的思路 将字典存放的数据 转成 数组存放,每个key值出现的次数,当做数组的索引,将数据存放进去。

代码实现:

//遍历数组
- (NSMutableDictionary *)dictinaryOrderByArray:(NSArray *)array {
    NSMutableDictionary *dicM = [NSMutableDictionary dictionary];
    for (NSString *numberS in array) {
        NSNumber *number = dicM[numberS];
        if (number == nil) {
           number = @0;
        }
        int value = number.intValue ;
        value++;
        [dicM setValue:[NSNumber numberWithInt:value] forKey:numberS];
    }
    return dicM;
}

- (void)getKOffenValue:(NSDictionary *)dic k:(int)k {
    //先创建跟字典个数相同的空数组集合
    NSMutableArray *arrayM = [NSMutableArray arrayWithCapacity:dic.count];
    for (int i = 0; i < dic.count; i++) {
        [arrayM addObject:[NSMutableArray array]];
    }
    //把key值对应的出现的次数放到那个次数为索引的数组中(类似于散列表),因为要考虑到可能有的出现次数会相同,所以最好用数组来存放
    NSArray *keys = dic.allKeys;
    for (NSString *keyString in keys) {
        NSNumber *number = dic[keyString];
        NSMutableArray *arrayInt = arrayM[number.integerValue];
        [arrayInt addObject:keyString];
        [arrayM replaceObjectAtIndex:number.intValue withObject:arrayInt];
    }
    //取出前k个高频数字
    NSMutableArray *arrayK = [NSMutableArray array];
    for (int i = arrayM.count - 1; i > 0 && arrayK.count < k; i--) {
        NSArray *array = arrayM[i];
        [arrayK addObjectsFromArray:array];
    }
    NSLog(@"array = %@", arrayK);
}


- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    NSArray *array = @[@"1", @"1", @"2", @"3", @"4", @"3", @"3"];
    [self getKOffenValue:[self dictinaryOrderByArray:array] k:2];
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值