Understanding Why Sometime an Array Can Excel a Map

Introduction

We have discussed in a previous article, in most common situation if we have to maintain two Arrays working consistantly, we should better use a Map instead. And that‘s the reason why Map is introduced at the first place. But there are also some cases an Array can excel a Map.

The first question is always, why do we care? We already feel comfortable of using a Map. The answer is Array will work more quickly than a Map. If we want to improve the speed, in some situation we can go back to using an Array. Array is fast, but not always we can use it. That is, when we working with english alphabet(a~z). If we use a Map in these situation, of course, it will works fine. But let‘s have a second thought, there are only 26 english letters. If we can store them as 0 ~ 25 by an Array‘s index, other than store them as "a"~"z" in the key section of a Map? Yes, we can appoint/arrange 0 is a, 1 is b, 2 is c, and so on, instead of storing real "a", "b" and "c". Base on this idea, finally, we can use an Array to make our application works more efficently. Because an Array is stored in a contiguous memory.

Let‘s have a look at two LeetCode question, helping us make more sense of the above idea.

LeetCode 1160

"Find Words That Can Be Formed by Characters"

You are given an array of strings words and a string chars.

A string is good if it can be formed by characters from chars (each character can only be used once).

Return the sum of lengths of all good strings in words.

Example 1:

Input: words = ["cat","bt","hat","tree"], chars = "atach"
Output: 6
Explanation:
The strings that can be formed are "cat" and "hat" so the answer is 3 + 3 = 6.

Example 2:

Input: words = ["hello","world","leetcode"], chars = "welldonehoneyr"
Output: 10
Explanation:
The strings that can be formed are "hello" and "world" so the answer is 5 + 5 = 10.

If we are using a Map:

func countCharacters(words []string, chars string) int {
    lengths := 0

    for _, word := range words {
        // reset charAvailable in each loop
        charAvailable:= make(map[string]int)
        for _, c := range chars {
            charAvailable[string(c)]++
        }

        fail := false
        for _, c := range word {
            num, _ := charAvailable[string(c)]
            if num > 0 {
                charAvailable[string(c)]--
            } else {
                fail = true
                break
            }
        }
        if !fail {
            lengths += len(word)
        }
    }

    return lengths
}

This solution is correct. Website shows that the speed is around 100ms, and faster than only 5% of Go users.

We can see each loop we have to reset the "charAvailable" Map and it is very time consuming.

With a little help of make() function‘s argument, we can change it into charAvailable := make(map[string]int, len(chars)/2).  This can help decrease 20ms of time consumping, but still have room for optimization.

We want two things‘s help to improve our speed:

1. If we can find other data struct faster than Map?

2. If we can initialize "charAvailable" only once, and copy it for each loop?

Firstly, here comes Slice backed by an Array. All the Other idea is exactly the same as above.

func countCharacters(words []string, chars string) int {
    lengths := 0

    for _, word := range words {
        // reset charAvailable in each loop
        charAvailable:= make([]int, 26)
        for _, c := range chars {
            charAvailable[c-‘a‘]++
        }

        fail := false
        for _, c := range word {
            if charAvailable[c-‘a‘] > 0 {
                charAvailable[c-‘a‘]--
            } else {
                fail = true
                break
            }
        }
        if !fail {
            lengths += len(word)
        }
    }

    return lengths
}

Website shows that the speed is around 10ms, and faster than 100% of Go users. It is good enough.

If we go further, we want to initialize "charAvailable" only once, instead of reset in reach loop.

So secondly, we will get to know a build in function called copy(). This function can make a value copy between two Slices, instead of pointer copy when we using "=" .

This function can make our code a little more clearly. We initialize "charAvailable" only once, before the loop. Website shows the speed of this process is also around 10ms.

func countCharacters(words []string, chars string) int {
    lengths := 0

    charAvailable:= make([]int, 26)
    for _, c := range chars {
        charAvailable[c-‘a‘]++
    }

    for _, word := range words {
        charAv := make([]int, 26)
        copy(charAv, charAvailable)

        fail := false
        for _, c := range word {
            if charAv[c-‘a‘] > 0 {
                charAv[c-‘a‘]--
            } else {
                fail = true
                break
            }
        }
        if !fail {
            lengths += len(word)
        }
    }

    return lengths
}

It is mostly the same as we use an Array. We already knew "=" between two Arrays will do value copy by default. Website shows speed is around 10ms also.

func countCharacters(words []string, chars string) int {
    lengths := 0

    charAvailable:= [26]int{}
    for _, c := range chars {
        charAvailable[c-‘a‘]++
    }

    for _, word := range words {
        charAv := charAvailable

        fail := false
        for _, c := range word {
            if charAv[c-‘a‘] > 0 {
                charAv[c-‘a‘]--
            } else {
                fail = true
                break
            }
        }
        if !fail {
            lengths += len(word)
        }
    }

    return lengths
}

  

原文地址:https://www.cnblogs.com/drvongoosewing/p/12232032.html

时间: 2024-12-16 12:11:20

Understanding Why Sometime an Array Can Excel a Map的相关文章

Go语言学习笔记(四) [array、slices、map]

日期:2014年7月22日 一.array[数组] 1.定义:array 由 [n]<type> 定义,n 标示 array 的长度,而 <type> 标示希望存储的内容的类型. 例如: var arr[10] int arr[0] = 1 arr[1] = 2 数组值类型的:将一个数组赋值给 另一个数组,会复制所有的元素.另外,当向函数内传递一个数组的时候,它将获得一个数组的副本,而不是数组的指针. 2.数组的复合声明.a :=[3]int{1,2,3}或简写为a:=[...]i

Go——array、slice和map的区别

参考文章:https://go101.org/article/container.html 1. 文字表示 N:一般称作长度,表示元素的个数. T:表示元素的类型,可以是任意类型. K:在map中表示索引的类型,可以是任意可比较的类型. 2. 例子 3. 正篇 如[1]所示,宏观上来看,array.slice.map的区别在于: a. array的定义是有长度的 b. slice的定义没有长度 c. map的定义没有长度 三种数据类型中的每一个元素都有一个对应的key值,这些key值叫做索引(i

【转载】Java集合类Array、List、Map区别和联系

Java集合类主要分为以下三类: 第一类:Array.Arrays第二类:Collection :List.Set第三类:Map :HashMap.HashTable 一.Array , Arrays Java所有"存储及随机访问一连串对象"的做法,array是最有效率的一种. 1.效率高,但容量固定且无法动态改变.array还有一个缺点是,无法判断其中实际存有多少元素,length只是告诉我们array的容量. 2.Java中有一个Arrays类,专门用来操作array .array

Go 语言中的 Array,Slice,Map 和 Set

转自:https://se77en.cc/ Array(数组) 内部机制 在 Go 语言中数组是固定长度的数据类型,它包含相同类型的连续的元素,这些元素可以是内建类型,像数字和字符串,也可以是结构类型,元素可以通过唯一的索引值访问,从 0 开始. 数组是很有价值的数据结构,因为它的内存分配是连续的,内存连续意味着可是让它在 CPU 缓存中待更久,所以迭代数组和移动元素都会非常迅速. 数组声明和初始化 通过指定数据类型和元素个数(数组长度)来声明数组. // 声明一个长度为5的整数数组 var a

java 读取excel(Map结构)xls

package com.sun.test; import java.io.FileInputStream;import java.io.FileNotFoundException;import java.io.IOException;import java.io.InputStream;import java.util.Date;import java.util.HashMap;import java.util.Map; import org.apache.poi.hssf.usermodel.

表示集合的数据结构:数组(Array),对象(Object),Map和Set

Map和Set是ES6标准新增的数据类型 Map: 是一组键值对的结构,使用一个二维数组来初始化Map,例如: var m = new Map([['xiaohong',100],['xiaolan',99],['xiaoming',108]]); 或者直接初始化一个空Map: var m = new Map(); m.set('xiaoli',98); m.get('xiaoli'); // 98 m.delete('xiaoli');//删除xiaoli这个键值对 m.get('xiaoli

[转]解析json:与array,list,map,bean,xml相互转化

一.解析json之net.sf.json 下载地址 使用netsfjson需要导入的包 JSONObject JSONArray JavaBean与json字符串互转 List与json字符串互转 Map与json字符串互转 JSONArray与List互转 JSONArray与数组互转 XML与JSON互转 下载地址 [plain] view plain copy 本次使用版本:http://sourceforge.net/projects/json-lib/files/json-lib/js

用excel.php类库导出excel文件

excel.php是个小型的php类库,可以满足基本的从数据库中取出数据然后导出xls格式的excel文件,代码如下: 1 class Excel { 2 public $filename = 'excel'; 3 public $custom_titles; 4 5 public function make_from_db($db_results) 6 { 7 $data = NULL; 8 $fields = $db_results->field_data(); 9 if ($db_resu

poi excel文件上传并解析xls文件

1.jsp页面 <form action="hw/pe_xls_upload" method="post" enctype="multipart/form-data" > <table> <tr> <td>导入硬件序列号/密码Excel文件:</td> <td><input name="hwFile" type="file"/&g