hashmap使用方法和罗马数转int数

该博客主要介绍了如何利用HashMap解决LeetCode13题——罗马数字转整数,并探讨了HashMap的创建、插入、获取、更新等操作,以及Java中使用object类型的考虑。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

LeetCode13题,罗马数字转成数字

罗马数字包含以下七种字符: I, V, X, L,C,D 和 M。

字符 数值
I 1
V 5
X 10
L 50
C 100
D 500
M 1000
例如, 罗马数字 2 写做 II ,即为两个并列的 1。12 写做 XII ,即为 X + II 。 27 写做 XXVII, 即为 XX + V + II 。

通常情况下,罗马数字中小的数字在大的数字的右边。但也存在特例,例如 4 不写做 IIII,而是 IV。数字 1 在数字 5 的左边,所表示的数等于大数 5 减小数 1 得到的数值 4 。同样地,数字 9 表示为 IX。这个特殊的规则只适用于以下六种情况:

I 可以放在 V (5) 和 X (10) 的左边,来表示 4 和 9。
X 可以放在 L (50) 和 C (100) 的左边,来表示 40 和 90。
C 可以放在 D (500) 和 M (1000) 的左边,来表示 400 和 900。
给定一个罗马数字,将其转换成整数。输入确保在 1 到 3999 的范围内。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/roman-to-integer
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

解题思路

原本用了两个数组分别储存13中数值情况和数值,接着学了map和set,想到这个题目或许红hashmap能更节省空间。

public static int romanToInt(String s) {
		HashMap<String,Integer> hashmap = new HashMap();
		hashmap.put("I",1);
		hashmap.put("IV",4);
		hashmap.put("V",5);
		hashmap.put("IX",9);
		hashmap.put("X",10);
		hashmap.put("XL",40);
		hashmap.put("L",50);
		hashmap.put("XC",90);
		hashmap.put("C",100);
		hashmap.put("CD",400);
		hashmap.put("D",500);
		hashmap.put("CM",900);
		hashmap.put("M",1000);
		int num = 0;
		for(int i=0;i<s.length();) {
			if(hashmap.containsKey(s.substring(i, i+1))) {
				if(i+2<=s.length()&&hashmap.containsKey(s.substring(i, i+2))) {
					num=num+hashmap.get(s.substring(i,i+2));
					i=i+2;
				}else {
					num=num+hashmap.get(s.substring(i,i+1));
					i++;
				}
			}
		}
		return num;
	}

采用hashmap确实能大幅简化代码量和使用空间。

hashmap

创建方法

HashMap<K,V> hashmap=new Hashmap();

创建时小tip

K和V,即key和value的数据类型一定要填写,遇到一个问题是如果未填写,插入数据类型是String和Int,get到的value确实是Integer类型的数据结构,但是无法与int类型变量相加减

public static void main(String[] args) {
		// TODO Auto-generated method stub
		String s = "";
		System.out.println(LeetCode13.romanToInt(s));
		HashMap hashmap = new HashMap();
		hashmap.put("I",1);
		System.out.println(hashmap.get("I").getClass());//此处输出为class java.lang.Integer
		int num = hashmap.get("I");//此处报错Type mismatch: cannot convert from Object to int
	}

更新:小tip的解释

未指定数据类型时,hashmap的get方法返回的是未定义的变量,即为object变量,虽然指向的是一个Integer类型对象(getclass返回Integer的原因),但是未进行类型强转时一个object变量无法直接进行操作。错误提示也为我们指明了原因:
在这里插入图片描述

关于Java的思考:Java中大部分源码都会使用object类型变量,为什么?object是所有类的父变量,这句话是否没有看上去那么简单。

插入:put和putIfAbsent

HashMap插入时不会储存插入次序,也无法进行排序
方法为hashmap.put(K key,V value);如果key对应的vaule存在,会覆盖掉原有的value值
public V putIfAbsent(K key, V value) :只有当前key值对应的value不存在或当前key值不存在,则插入。

public V put(K key, V value) {
        return putVal(hash(key), key, value, false, true);
    }

    /**
     * Implements Map.put and related methods.
     *
     * @param hash hash for key
     * @param key the key
     * @param value the value to put
     * @param onlyIfAbsent if true, don't change existing value
     * @param evict if false, the table is in creation mode.
     * @return previous value, or null if none
     */
    final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
                   boolean evict) {
        Node<K,V>[] tab; Node<K,V> p; int n, i;
        if ((tab = table) == null || (n = tab.length) == 0)
            n = (tab = resize()).length;
        if ((p = tab[i = (n - 1) & hash]) == null)
            tab[i] = newNode(hash, key, value, null);
        else {
            Node<K,V> e; K k;
            if (p.hash == hash &&
                ((k = p.key) == key || (key != null && key.equals(k))))
                e = p;
            else if (p instanceof TreeNode)
                e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
            else {
                for (int binCount = 0; ; ++binCount) {
                    if ((e = p.next) == null) {
                        p.next = newNode(hash, key, value, null);
                        if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
                            treeifyBin(tab, hash);
                        break;
                    }
                    if (e.hash == hash &&
                        ((k = e.key) == key || (key != null && key.equals(k))))
                        break;
                    p = e;
                }
            }
            if (e != null) { // existing mapping for key
                V oldValue = e.value;
                if (!onlyIfAbsent || oldValue == null)
                    e.value = value;
                afterNodeAccess(e);
                return oldValue;
            }
        }
        ++modCount;
        if (++size > threshold)
            resize();
        afterNodeInsertion(evict);
        return null;
    }

获得value:get与getOrDefault

方法:hashmap.get(key);返回value对象
方法:hashmap.getOrDefault(object key,V defaultValue);
当hashmap中有对应的key值时,返回对应的value对象,如果找不到,返回defaultValue

 public V getOrDefault(Object key, V defaultValue) {
        Node<K,V> e;
        return (e = getNode(hash(key), key)) == null ? defaultValue : e.value;
    }

public V get(Object key) {
        Node<K,V> e;
        return (e = getNode(hash(key), key)) == null ? null : e.value;
    }

    /**
     * Implements Map.get and related methods.
     *
     * @param hash hash for key
     * @param key the key
     * @return the node, or null if none
     */
    final Node<K,V> getNode(int hash, Object key) {
        Node<K,V>[] tab; Node<K,V> first, e; int n; K k;
        if ((tab = table) != null && (n = tab.length) > 0 &&
            (first = tab[(n - 1) & hash]) != null) {
            if (first.hash == hash && // always check first node
                ((k = first.key) == key || (key != null && key.equals(k))))
                return first;
            if ((e = first.next) != null) {
                if (first instanceof TreeNode)
                    return ((TreeNode<K,V>)first).getTreeNode(hash, key);
                do {
                    if (e.hash == hash &&
                        ((k = e.key) == key || (key != null && key.equals(k))))
                        return e;
                } while ((e = e.next) != null);
            }
        }
        return null;
    }

查看是否有key值对应的键值对:containsKey

boolean b = hashmap.containsKey(key);

 public boolean containsKey(Object key) {
        return getNode(hash(key), key) != null;
    }
getNode方法见get方法源码

查看是否有value值对应的键值对:containsValue

    public boolean containsValue(Object value) {
        Node<K,V>[] tab; V v;
        if ((tab = table) != null && size > 0) {
            for (int i = 0; i < tab.length; ++i) {
                for (Node<K,V> e = tab[i]; e != null; e = e.next) {
                    if ((v = e.value) == value ||
                        (value != null && value.equals(v)))
                        return true;
                }
            }
        }
        return false;
    }

清空:clear()

    public void clear() {
        Node<K,V>[] tab;
        modCount++;
        if ((tab = table) != null && size > 0) {
            size = 0;
            for (int i = 0; i < tab.length; ++i)
                tab[i] = null;
        }
    }

移除某一键值对:remove

当remove(object key)时,如成功移除,返回value值,如不存在key值,返回null。
当remove(object key,object value)时,成功返回true,失败返回false

public V remove(Object key) {
        Node<K,V> e;
        return (e = removeNode(hash(key), key, null, false, true)) == null ?
            null : e.value;
    }
    public boolean remove(Object key, Object value) {
        return removeNode(hash(key), key, value, true, true) != null;
    }

获取数据类型:getClass

方法:Class<?> getClass
实例:hashmap.getCalss();
hashmap.get(object key).getClass();

查看map是否为空:isEmpty

    public boolean isEmpty() {
        return size == 0;
    }

返回所有value:values

实例:
		HashMap hashmap = new HashMap();
		hashmap.put(2,1);
		hashmap.put(1,2);
		System.out.println(hashmap.values());
//输出为[2,1]

public Collection<V> values() {
        Collection<V> vs = values;
        if (vs == null) {
            vs = new Values();
            values = vs;
        }
        return vs;
    }

获取元素个数:size(不是hashmap空间个数)

public int size() {
    return size;
}

返回所有Key

public Set<K> keySet() {
        Set<K> ks = keySet;
        if (ks == null) {
            ks = new KeySet();
            keySet = ks;
        }
        return ks;
    }

返回所有键值对:entrySet

    public Set<Map.Entry<K,V>> entrySet() {
        Set<Map.Entry<K,V>> es;
        return (es = entrySet) == null ? (entrySet = new EntrySet()) : es;
    }

三种返回实例和直接输出map:

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		String s = "";
		HashMap<Character,Integer> hashmap = new HashMap();
		hashmap.put('a',1);
		hashmap.put('b',2);
		System.out.println(hashmap.keySet());
		System.out.println(hashmap.values());
		System.out.println(hashmap.entrySet());
		System.out.println(hashmap);
	}
//输出:
[a, b]
[1, 2]
[a=1, b=2]
{a=1, b=2}

添加另一个同一类型的map下的所有值:hashmap.putAll(m)

示例:hashmap1.putAll(hashmap)

    public void putAll(Map<? extends K, ? extends V> m) {
        putMapEntries(m, true);
    }

    final void putMapEntries(Map<? extends K, ? extends V> m, boolean evict) {
        int s = m.size();
        if (s > 0) {
            if (table == null) { // pre-size
                float ft = ((float)s / loadFactor) + 1.0F;
                int t = ((ft < (float)MAXIMUM_CAPACITY) ?
                         (int)ft : MAXIMUM_CAPACITY);
                if (t > threshold)
                    threshold = tableSizeFor(t);
            }
            else if (s > threshold)
                resize();
            for (Map.Entry<? extends K, ? extends V> e : m.entrySet()) {
                K key = e.getKey();
                V value = e.getValue();
                putVal(hash(key), key, value, false, evict);
            }
        }
    }

替换key对应的value:replace

  1. public boolean replace(K key, V oldValue, V newValue)
    如果k-v键值对正确,替换value,返回true
    如果k-v键值对错误,不替换,返回false
    2.public V replace(K key, V value)
    如果k存在,替换,返回value
    如果k不存在,返回null
    public boolean replace(K key, V oldValue, V newValue) {
        Node<K,V> e; V v;
        if ((e = getNode(hash(key), key)) != null &&
            ((v = e.value) == oldValue || (v != null && v.equals(oldValue)))) {
            e.value = newValue;
            afterNodeAccess(e);
            return true;
        }
        return false;
    }

    @Override
    public V replace(K key, V value) {
        Node<K,V> e;
        if ((e = getNode(hash(key), key)) != null) {
            V oldValue = e.value;
            e.value = value;
            afterNodeAccess(e);
            return oldValue;
        }
        return null;
    }

hashmap的函数式替换:replaceAll(IDE报错+无法理解ing)

    public void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {
        Node<K,V>[] tab;
        if (function == null)
            throw new NullPointerException();
        if (size > 0 && (tab = table) != null) {
            int mc = modCount;
            for (int i = 0; i < tab.length; ++i) {
                for (Node<K,V> e = tab[i]; e != null; e = e.next) {
                    e.value = function.apply(e.key, e.value);
                }
            }
            if (modCount != mc)
                throw new ConcurrentModificationException();
        }
    }

hashmap的克隆:clone

返回的是一个object类型的变量,指向一个HashMap<K,V>的对象
实例:

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		String s = "";
		System.out.println(LeetCode13.romanToInt(s));
		HashMap<Character,Integer> hashmap = new HashMap();
		hashmap.put('a',1);
		hashmap.put('b',2);
		System.out.println(hashmap.clone());
		HashMap<Character,Integer> hashmap1 =new HashMap();
		hashmap1=(HashMap<Character,Integer>)hashmap.clone();
		System.out.println(hashmap1);
	}
//输出:
{a=1, b=2}
{a=1, b=2}
    public Object clone() {
        HashMap<K,V> result;
        try {
            result = (HashMap<K,V>)super.clone();
        } catch (CloneNotSupportedException e) {
            // this shouldn't happen, since we are Cloneable
            throw new InternalError(e);
        }
        result.reinitialize();
        result.putMapEntries(this, false);
        return result;
    }

hashmap的函数式替换:compute

compute 方法更适用于更新 key 关联的 value 时,新值依赖于旧值的情况
v会等于返回回来的值,所以返回值必须是V类型,或可以被包装为V类型

实例:

		HashMap<Character,Integer> hashmap = new HashMap();
		hashmap.put('a',1);
		hashmap.put('b',2);
		hashmap.putIfAbsent('c',3);
		hashmap.put('b',4);
		hashmap.compute('d', (k,v)->{
			if(k=='a') 
				v=100;
			Integer b=300;
			return b;
			});
		System.out.println(hashmap);
//{a=1, b=4, c=3, d=300}

源码:
    public V compute(K key,
                     BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
        if (remappingFunction == null)
            throw new NullPointerException();
        int hash = hash(key);
        Node<K,V>[] tab; Node<K,V> first; int n, i;
        int binCount = 0;
        TreeNode<K,V> t = null;
        Node<K,V> old = null;
        if (size > threshold || (tab = table) == null ||
            (n = tab.length) == 0)
            n = (tab = resize()).length;
        if ((first = tab[i = (n - 1) & hash]) != null) {
            if (first instanceof TreeNode)
                old = (t = (TreeNode<K,V>)first).getTreeNode(hash, key);
            else {
                Node<K,V> e = first; K k;
                do {
                    if (e.hash == hash &&
                        ((k = e.key) == key || (key != null && key.equals(k)))) {
                        old = e;
                        break;
                    }
                    ++binCount;
                } while ((e = e.next) != null);
            }
        }
        V oldValue = (old == null) ? null : old.value;
        V v = remappingFunction.apply(key, oldValue);
        if (old != null) {
            if (v != null) {
                old.value = v;
                afterNodeAccess(old);
            }
            else
                removeNode(hash, key, null, false, true);
        }
        else if (v != null) {
            if (t != null)
                t.putTreeVal(this, tab, hash, key, v);
            else {
                tab[i] = newNode(hash, key, v, first);
                if (binCount >= TREEIFY_THRESHOLD - 1)
                    treeifyBin(tab, hash);
            }
            ++modCount;
            ++size;
            afterNodeInsertion(true);
        }
        return v;
    }

compute的扩展:computeIfAbsent和computeIfPresent

public V computeIfAbsent(key, mappingFunction):只有当key对应的键值对不存在时,才进行操作
public V computeIfPresent(key, mappingFunction):只有但key对应的键值对存在时,才进行操作

map的迭代:forEach

public void forEach(BiConsumer<? super K, ? super V> action)



		hashmap.forEach((k,v)->{
			System.out.print(k+":"+v);
			v=999;
		});//v不会变
		hashmap.forEach((k,v)->{
			System.out.print(k+":"+v);
		});
//注:foreach方法无法直接向map传递值,不过如果你在函数中使用put还是能传值的

map的merge:待(还)补(不)充(会)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值