The gas savings with 1155 come from not keeping track of an additional variable which in 721 is accessible through 'balanceOf'.
If you were trying to adapt 1155 to make it non-fungible, like 721 (if you only ever mint one of a certain id), you only have one mapping
[uint256 (id) => address (user) => uint256 (balance)], where balance is either 1 or 0.
With 721, you keep track of the ownerships through a mapping
[uint256 (id) => address (owner)]. There is a second mapping [address (user) => uint256 (balance)] that in this case, keeps track of how many NFTs the user owns. This lets you conveniently query whether a user owns an NFT of a certain collection (Collabland discord bot queries this value through 'balanceOf' to give a member role to users). So mostly it's being used for verification processes (I know of projects that make use of this on-chain). It is however not strictly necessary, since you could always either provide an id that you know you own (which could then also easily verified on-chain), and you can provide an O(N) implementation (not callable on-chain, because it would cost too much gas) which simply loops through all ids and counts how many you own. There have been multiple ERC721 implementations floating around that do exactly this (saving gas by not tracking this second mapping).
This balance variable does not exist in 1155. The equivalent here would be to have a variable that would keep track of unique balances.
In summary, 1155 does not use a second mapping to keep track of unique balances like 721 does. This means every transfer has less reads/writes. In 1155 it's only two (ownership/balances [from], [to]), versus 3 in 721 (ownership, balance[from], balance[to]). Light versions of ERC721 can cut down to 1 variable (only ownership) and have an O(N) balanceOf implementation.